Repository: eclipse/kura Branch: develop Commit: 84cc093efcf4 Files: 2431 Total size: 10.6 MB Directory structure: gitextract_mpzc0g92/ ├── .gitattributes ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ ├── copyright-config.yml │ ├── release_notes_template/ │ │ ├── helper.hbs │ │ └── template.hbs │ ├── version_uptick_configs/ │ │ ├── uptick_major_on_develop_branch.yml │ │ ├── uptick_minor_on_develop_branch.yml │ │ ├── uptick_patch_on_maintenance_branch.yml │ │ ├── uptick_snapshot_to_patch_release.yml │ │ └── uptick_snapshot_to_release.yml │ └── workflows/ │ ├── backport.yml │ ├── copyright-check.yml │ ├── force-merge.yml │ ├── kura-core-sbom.yml │ ├── release-notes.yml │ ├── semantic-pr.yml │ ├── stale-issues.yml │ ├── target-platform-sbom.yml │ └── version-uptick.yml ├── .gitignore ├── .jenkins/ │ └── nexusUtils.groovy ├── AGENTS.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Jenkinsfile ├── LICENSE ├── NOTICE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── SECURITY.md ├── build-all.sh ├── checkstyle_checks.xml ├── kura/ │ ├── distrib/ │ │ ├── .gitignore │ │ ├── RELEASE_NOTES.txt │ │ ├── aarch64-core/ │ │ │ └── pom.xml │ │ ├── core-dp/ │ │ │ └── pom.xml │ │ ├── eclipse_license.txt │ │ ├── epl-v20.html │ │ ├── notice.html │ │ ├── pom.xml │ │ ├── src/ │ │ │ └── main/ │ │ │ └── resources/ │ │ │ ├── filtered/ │ │ │ │ └── pkg/ │ │ │ │ ├── bin/ │ │ │ │ │ └── start_kura.sh │ │ │ │ ├── framework/ │ │ │ │ │ └── kura.properties │ │ │ │ └── install/ │ │ │ │ ├── kura.service │ │ │ │ └── kura_install.sh │ │ │ └── unfiltered/ │ │ │ ├── deb/ │ │ │ │ └── control/ │ │ │ │ ├── control │ │ │ │ ├── postinst │ │ │ │ ├── preinst │ │ │ │ └── prerm │ │ │ └── pkg/ │ │ │ ├── bin/ │ │ │ │ └── gen_config_ini.sh │ │ │ ├── framework/ │ │ │ │ └── config.ini │ │ │ ├── install/ │ │ │ │ ├── customize-installation.sh │ │ │ │ ├── customize_kura_properties.py │ │ │ │ ├── kura-tmpfiles.conf │ │ │ │ ├── manage_kura_users.sh │ │ │ │ ├── network_tools.py │ │ │ │ └── snapshot_0.xml │ │ │ ├── log4j/ │ │ │ │ └── log4j.xml │ │ │ ├── packages/ │ │ │ │ └── .gitkeep │ │ │ └── user/ │ │ │ ├── kura_custom.properties │ │ │ └── security/ │ │ │ └── cacerts.ks │ │ └── x86_64-core/ │ │ └── pom.xml │ ├── emulator/ │ │ ├── org.eclipse.kura.emulator/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── emulator.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── emulator/ │ │ │ │ └── Emulator.java │ │ │ └── resources/ │ │ │ ├── kura.properties │ │ │ ├── log4j.xml │ │ │ └── snapshot_0.xml │ │ ├── org.eclipse.kura.emulator.clock/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── clock.xml │ │ │ │ └── metatype/ │ │ │ │ └── org.eclipse.kura.clock.ClockService.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── clock/ │ │ │ └── ClockServiceImpl.java │ │ ├── org.eclipse.kura.emulator.gpio/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── gpio.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── gpio/ │ │ │ ├── EmulatedPin.java │ │ │ └── GpioServiceImpl.java │ │ ├── org.eclipse.kura.emulator.net/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── network.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── net/ │ │ │ ├── AbstractNetInterface.java │ │ │ ├── EmulatedNetworkServiceImpl.java │ │ │ ├── EthernetInterfaceImpl.java │ │ │ └── NetInterfaceAddressImpl.java │ │ ├── org.eclipse.kura.emulator.position/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── metatype/ │ │ │ │ │ └── org.eclipse.kura.position.PositionService.xml │ │ │ │ └── position.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── emulator/ │ │ │ │ └── position/ │ │ │ │ ├── GpsPoint.java │ │ │ │ ├── GpsXmlHandler.java │ │ │ │ └── PositionServiceImpl.java │ │ │ └── resources/ │ │ │ ├── boston.gpx │ │ │ ├── denver.gpx │ │ │ ├── paris.gpx │ │ │ └── test.gpx │ │ ├── org.eclipse.kura.emulator.usb/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── usb.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── usb/ │ │ │ └── UsbServiceImpl.java │ │ ├── org.eclipse.kura.emulator.watchdog/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── metatype/ │ │ │ │ │ └── org.eclipse.kura.watchdog.WatchdogService.xml │ │ │ │ └── watchdog.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── watchdog/ │ │ │ ├── CriticalServiceImpl.java │ │ │ └── WatchdogServiceImpl.java │ │ └── pom.xml │ ├── kura-pde-deps/ │ │ └── pom.xml │ ├── org.eclipse.kura.api/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ ├── KuraBluetoothBeaconAdvertiserNotAvailable.java │ │ │ ├── KuraBluetoothCommandException.java │ │ │ ├── KuraBluetoothConnectionException.java │ │ │ ├── KuraBluetoothDiscoveryException.java │ │ │ ├── KuraBluetoothIOException.java │ │ │ ├── KuraBluetoothNotificationException.java │ │ │ ├── KuraBluetoothPairException.java │ │ │ ├── KuraBluetoothRemoveException.java │ │ │ ├── KuraBluetoothResourceNotFoundException.java │ │ │ ├── KuraConnectException.java │ │ │ ├── KuraConnectionStatus.java │ │ │ ├── KuraDisconnectException.java │ │ │ ├── KuraErrorCode.java │ │ │ ├── KuraException.java │ │ │ ├── KuraIOException.java │ │ │ ├── KuraInvalidMessageException.java │ │ │ ├── KuraInvalidMetricTypeException.java │ │ │ ├── KuraNotConnectedException.java │ │ │ ├── KuraPartialSuccessException.java │ │ │ ├── KuraProcessExecutionErrorException.java │ │ │ ├── KuraRuntimeException.java │ │ │ ├── KuraStoreCapacityReachedException.java │ │ │ ├── KuraStoreException.java │ │ │ ├── KuraTimeoutException.java │ │ │ ├── KuraTooManyInflightMessagesException.java │ │ │ ├── KuraUnsupportedModemException.java │ │ │ ├── ai/ │ │ │ │ └── inference/ │ │ │ │ ├── InferenceEngineMetricsService.java │ │ │ │ ├── InferenceEngineService.java │ │ │ │ ├── ModelInfo.java │ │ │ │ ├── ModelInfoBuilder.java │ │ │ │ ├── Tensor.java │ │ │ │ ├── TensorDescriptor.java │ │ │ │ └── TensorDescriptorBuilder.java │ │ │ ├── annotation/ │ │ │ │ ├── Extensible.java │ │ │ │ ├── Immutable.java │ │ │ │ ├── NotThreadSafe.java │ │ │ │ ├── Nullable.java │ │ │ │ ├── ThreadSafe.java │ │ │ │ └── package-info.java │ │ │ ├── asset/ │ │ │ │ ├── Asset.java │ │ │ │ ├── AssetConfiguration.java │ │ │ │ ├── AssetService.java │ │ │ │ └── package-info.java │ │ │ ├── audit/ │ │ │ │ ├── AuditConstants.java │ │ │ │ ├── AuditContext.java │ │ │ │ └── package-info.java │ │ │ ├── bluetooth/ │ │ │ │ └── le/ │ │ │ │ ├── BluetoothLeAdapter.java │ │ │ │ ├── BluetoothLeDevice.java │ │ │ │ ├── BluetoothLeGattCharacteristic.java │ │ │ │ ├── BluetoothLeGattCharacteristicProperties.java │ │ │ │ ├── BluetoothLeGattDescriptor.java │ │ │ │ ├── BluetoothLeGattService.java │ │ │ │ ├── BluetoothLeService.java │ │ │ │ ├── BluetoothTransportType.java │ │ │ │ ├── beacon/ │ │ │ │ │ ├── AdvertisingReportAddressType.java │ │ │ │ │ ├── AdvertisingReportEventType.java │ │ │ │ │ ├── AdvertisingReportPhy.java │ │ │ │ │ ├── AdvertisingReportRecord.java │ │ │ │ │ ├── BluetoothLeBeacon.java │ │ │ │ │ ├── BluetoothLeBeaconAdvertiser.java │ │ │ │ │ ├── BluetoothLeBeaconDecoder.java │ │ │ │ │ ├── BluetoothLeBeaconEncoder.java │ │ │ │ │ ├── BluetoothLeBeaconManager.java │ │ │ │ │ ├── BluetoothLeBeaconScanner.java │ │ │ │ │ ├── BluetoothLeBeaconService.java │ │ │ │ │ ├── listener/ │ │ │ │ │ │ ├── BluetoothLeBeaconListener.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── certificate/ │ │ │ │ ├── CertificatesService.java │ │ │ │ ├── KuraCertificateEntry.java │ │ │ │ ├── KuraPrivateKeyEntry.java │ │ │ │ ├── enrollment/ │ │ │ │ │ └── EnrollmentService.java │ │ │ │ └── package-info.java │ │ │ ├── channel/ │ │ │ │ ├── Channel.java │ │ │ │ ├── ChannelFlag.java │ │ │ │ ├── ChannelRecord.java │ │ │ │ ├── ChannelStatus.java │ │ │ │ ├── ChannelType.java │ │ │ │ ├── ScaleOffsetType.java │ │ │ │ ├── listener/ │ │ │ │ │ ├── ChannelEvent.java │ │ │ │ │ ├── ChannelListener.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── clock/ │ │ │ │ ├── ClockEvent.java │ │ │ │ ├── ClockService.java │ │ │ │ └── package-info.java │ │ │ ├── cloud/ │ │ │ │ ├── CloudCallService.java │ │ │ │ ├── CloudClient.java │ │ │ │ ├── CloudClientListener.java │ │ │ │ ├── CloudConnectionEstablishedEvent.java │ │ │ │ ├── CloudConnectionLostEvent.java │ │ │ │ ├── CloudPayloadEncoding.java │ │ │ │ ├── CloudPayloadProtoBufDecoder.java │ │ │ │ ├── CloudPayloadProtoBufEncoder.java │ │ │ │ ├── CloudService.java │ │ │ │ ├── Cloudlet.java │ │ │ │ ├── CloudletTopic.java │ │ │ │ ├── factory/ │ │ │ │ │ ├── CloudServiceFactory.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── cloudconnection/ │ │ │ │ ├── CloudConnectionConstants.java │ │ │ │ ├── CloudConnectionManager.java │ │ │ │ ├── CloudEndpoint.java │ │ │ │ ├── factory/ │ │ │ │ │ ├── CloudConnectionFactory.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── listener/ │ │ │ │ │ ├── CloudConnectionListener.java │ │ │ │ │ ├── CloudDeliveryListener.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── message/ │ │ │ │ │ ├── KuraMessage.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── package-info.java │ │ │ │ ├── publisher/ │ │ │ │ │ ├── CloudNotificationPublisher.java │ │ │ │ │ ├── CloudPublisher.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── request/ │ │ │ │ │ ├── RequestHandler.java │ │ │ │ │ ├── RequestHandlerContext.java │ │ │ │ │ ├── RequestHandlerContextConstants.java │ │ │ │ │ ├── RequestHandlerMessageConstants.java │ │ │ │ │ ├── RequestHandlerRegistry.java │ │ │ │ │ └── package-info.java │ │ │ │ └── subscriber/ │ │ │ │ ├── CloudSubscriber.java │ │ │ │ ├── listener/ │ │ │ │ │ ├── CloudSubscriberListener.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── comm/ │ │ │ │ ├── CommConnection.java │ │ │ │ ├── CommURI.java │ │ │ │ └── package-info.java │ │ │ ├── command/ │ │ │ │ ├── CommandService.java │ │ │ │ ├── PasswordCommandService.java │ │ │ │ └── package-info.java │ │ │ ├── configuration/ │ │ │ │ ├── ComponentConfiguration.java │ │ │ │ ├── ConfigurableComponent.java │ │ │ │ ├── ConfigurationService.java │ │ │ │ ├── KuraConfigReadyEvent.java │ │ │ │ ├── KuraNetConfigReadyEvent.java │ │ │ │ ├── Password.java │ │ │ │ ├── SelfConfiguringComponent.java │ │ │ │ ├── metatype/ │ │ │ │ │ ├── AD.java │ │ │ │ │ ├── Attribute.java │ │ │ │ │ ├── Designate.java │ │ │ │ │ ├── Icon.java │ │ │ │ │ ├── MetaData.java │ │ │ │ │ ├── OCD.java │ │ │ │ │ ├── OCDService.java │ │ │ │ │ ├── Option.java │ │ │ │ │ ├── Scalar.java │ │ │ │ │ ├── TObject.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── connection/ │ │ │ │ └── listener/ │ │ │ │ ├── ConnectionListener.java │ │ │ │ └── package-info.java │ │ │ ├── container/ │ │ │ │ ├── orchestration/ │ │ │ │ │ ├── ContainerConfiguration.java │ │ │ │ │ ├── ContainerInstanceDescriptor.java │ │ │ │ │ ├── ContainerNetworkConfiguration.java │ │ │ │ │ ├── ContainerOrchestrationService.java │ │ │ │ │ ├── ContainerPort.java │ │ │ │ │ ├── ContainerState.java │ │ │ │ │ ├── ImageConfiguration.java │ │ │ │ │ ├── ImageInstanceDescriptor.java │ │ │ │ │ ├── PasswordRegistryCredentials.java │ │ │ │ │ ├── PortInternetProtocol.java │ │ │ │ │ ├── RegistryCredentials.java │ │ │ │ │ ├── listener/ │ │ │ │ │ │ ├── ContainerOrchestrationServiceListener.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ └── package-info.java │ │ │ │ └── signature/ │ │ │ │ ├── ContainerSignatureValidationService.java │ │ │ │ ├── ValidationResult.java │ │ │ │ └── package-info.java │ │ │ ├── crypto/ │ │ │ │ ├── CryptoService.java │ │ │ │ └── package-info.java │ │ │ ├── data/ │ │ │ │ ├── DataService.java │ │ │ │ ├── DataServiceListener.java │ │ │ │ ├── DataTransportListener.java │ │ │ │ ├── DataTransportService.java │ │ │ │ ├── DataTransportToken.java │ │ │ │ ├── listener/ │ │ │ │ │ ├── DataServiceListener.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── package-info.java │ │ │ │ └── transport/ │ │ │ │ └── listener/ │ │ │ │ ├── DataTransportListener.java │ │ │ │ └── package-info.java │ │ │ ├── db/ │ │ │ │ ├── BaseDbService.java │ │ │ │ ├── H2DbService.java │ │ │ │ ├── keyvalue/ │ │ │ │ │ ├── KeyValueDbService.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── deployment/ │ │ │ │ └── hook/ │ │ │ │ ├── DeploymentHook.java │ │ │ │ ├── RequestContext.java │ │ │ │ └── package-info.java │ │ │ ├── driver/ │ │ │ │ ├── ChannelDescriptor.java │ │ │ │ ├── Driver.java │ │ │ │ ├── DriverService.java │ │ │ │ ├── PreparedRead.java │ │ │ │ ├── descriptor/ │ │ │ │ │ ├── DriverDescriptor.java │ │ │ │ │ ├── DriverDescriptorService.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── executor/ │ │ │ │ ├── Command.java │ │ │ │ ├── CommandExecutorService.java │ │ │ │ ├── CommandStatus.java │ │ │ │ ├── ExitStatus.java │ │ │ │ ├── Pid.java │ │ │ │ ├── PrivilegedExecutorService.java │ │ │ │ ├── Signal.java │ │ │ │ └── UnprivilegedExecutorService.java │ │ │ ├── gpio/ │ │ │ │ ├── GPIOService.java │ │ │ │ ├── KuraClosedDeviceException.java │ │ │ │ ├── KuraGPIODescription.java │ │ │ │ ├── KuraGPIODeviceException.java │ │ │ │ ├── KuraGPIODirection.java │ │ │ │ ├── KuraGPIOMode.java │ │ │ │ ├── KuraGPIOPin.java │ │ │ │ ├── KuraGPIOTrigger.java │ │ │ │ ├── KuraUnavailableDeviceException.java │ │ │ │ ├── PinStatusListener.java │ │ │ │ └── package-info.java │ │ │ ├── identity/ │ │ │ │ ├── AdditionalConfigurations.java │ │ │ │ ├── AssignedPermissions.java │ │ │ │ ├── IdentityConfiguration.java │ │ │ │ ├── IdentityConfigurationComponent.java │ │ │ │ ├── IdentityService.java │ │ │ │ ├── LoginBannerService.java │ │ │ │ ├── PasswordConfiguration.java │ │ │ │ ├── PasswordHash.java │ │ │ │ ├── PasswordStrengthRequirements.java │ │ │ │ ├── PasswordStrengthVerificationService.java │ │ │ │ ├── Permission.java │ │ │ │ ├── configuration/ │ │ │ │ │ └── extension/ │ │ │ │ │ ├── IdentityConfigurationExtension.java │ │ │ │ │ └── package-info.java │ │ │ │ └── package-info.java │ │ │ ├── linux/ │ │ │ │ └── udev/ │ │ │ │ ├── LinuxUdevListener.java │ │ │ │ ├── UdevEventType.java │ │ │ │ └── package-info.java │ │ │ ├── log/ │ │ │ │ ├── LogEntry.java │ │ │ │ ├── LogProvider.java │ │ │ │ ├── LogReader.java │ │ │ │ ├── listener/ │ │ │ │ │ └── LogListener.java │ │ │ │ └── package-info.java │ │ │ ├── marshalling/ │ │ │ │ ├── Marshaller.java │ │ │ │ ├── Unmarshaller.java │ │ │ │ └── package-info.java │ │ │ ├── message/ │ │ │ │ ├── KuraAlertPayload.java │ │ │ │ ├── KuraAlertSeverity.java │ │ │ │ ├── KuraAlertStatus.java │ │ │ │ ├── KuraApplicationTopic.java │ │ │ │ ├── KuraBirthPayload.java │ │ │ │ ├── KuraDeviceProfile.java │ │ │ │ ├── KuraDisconnectPayload.java │ │ │ │ ├── KuraPayload.java │ │ │ │ ├── KuraPosition.java │ │ │ │ ├── KuraRequestPayload.java │ │ │ │ ├── KuraResponsePayload.java │ │ │ │ ├── KuraTopic.java │ │ │ │ ├── package-info.java │ │ │ │ └── store/ │ │ │ │ ├── StoredMessage.java │ │ │ │ ├── package-info.java │ │ │ │ └── provider/ │ │ │ │ ├── MessageStore.java │ │ │ │ ├── MessageStoreProvider.java │ │ │ │ └── package-info.java │ │ │ ├── net/ │ │ │ │ ├── ConnectionInfo.java │ │ │ │ ├── EthernetInterface.java │ │ │ │ ├── EthernetMonitorService.java │ │ │ │ ├── IP4Address.java │ │ │ │ ├── IP6Address.java │ │ │ │ ├── IPAddress.java │ │ │ │ ├── LoopbackInterface.java │ │ │ │ ├── NetConfig.java │ │ │ │ ├── NetConfig4.java │ │ │ │ ├── NetConfig6.java │ │ │ │ ├── NetConfigIP.java │ │ │ │ ├── NetConfigIP4.java │ │ │ │ ├── NetConfigIP6.java │ │ │ │ ├── NetInterface.java │ │ │ │ ├── NetInterfaceAddedEvent.java │ │ │ │ ├── NetInterfaceAddress.java │ │ │ │ ├── NetInterfaceAddressConfig.java │ │ │ │ ├── NetInterfaceConfig.java │ │ │ │ ├── NetInterfaceRemovedEvent.java │ │ │ │ ├── NetInterfaceState.java │ │ │ │ ├── NetInterfaceStateChangedEvent.java │ │ │ │ ├── NetInterfaceStatus.java │ │ │ │ ├── NetInterfaceType.java │ │ │ │ ├── NetProtocol.java │ │ │ │ ├── NetRouterMode.java │ │ │ │ ├── NetworkAdminService.java │ │ │ │ ├── NetworkPair.java │ │ │ │ ├── NetworkService.java │ │ │ │ ├── NetworkState.java │ │ │ │ ├── NetworkStateChangedEvent.java │ │ │ │ ├── dhcp/ │ │ │ │ │ ├── DhcpLease.java │ │ │ │ │ ├── DhcpServer.java │ │ │ │ │ ├── DhcpServerCfg.java │ │ │ │ │ ├── DhcpServerCfgIP.java │ │ │ │ │ ├── DhcpServerCfgIP4.java │ │ │ │ │ ├── DhcpServerCfgIP6.java │ │ │ │ │ ├── DhcpServerConfig.java │ │ │ │ │ ├── DhcpServerConfig4.java │ │ │ │ │ ├── DhcpServerConfig6.java │ │ │ │ │ ├── DhcpServerConfigIP.java │ │ │ │ │ ├── DhcpServerConfigIP4.java │ │ │ │ │ ├── DhcpServerConfigIP6.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── dns/ │ │ │ │ │ ├── DnsMonitorService.java │ │ │ │ │ ├── DnsServerConfig.java │ │ │ │ │ ├── DnsServerConfig4.java │ │ │ │ │ ├── DnsServerConfig6.java │ │ │ │ │ ├── DnsServerConfigIP.java │ │ │ │ │ ├── DnsServerConfigIP4.java │ │ │ │ │ ├── DnsServerConfigIP6.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── firewall/ │ │ │ │ │ ├── FirewallAutoNatConfig.java │ │ │ │ │ ├── FirewallNatConfig.java │ │ │ │ │ ├── FirewallOpenPortConfig.java │ │ │ │ │ ├── FirewallOpenPortConfig4.java │ │ │ │ │ ├── FirewallOpenPortConfig6.java │ │ │ │ │ ├── FirewallOpenPortConfigIP.java │ │ │ │ │ ├── FirewallOpenPortConfigIP4.java │ │ │ │ │ ├── FirewallOpenPortConfigIP6.java │ │ │ │ │ ├── FirewallPortForwardConfig.java │ │ │ │ │ ├── FirewallPortForwardConfig4.java │ │ │ │ │ ├── FirewallPortForwardConfig6.java │ │ │ │ │ ├── FirewallPortForwardConfigIP.java │ │ │ │ │ ├── FirewallPortForwardConfigIP4.java │ │ │ │ │ ├── FirewallPortForwardConfigIP6.java │ │ │ │ │ ├── RuleType.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── modem/ │ │ │ │ │ ├── CellularModem.java │ │ │ │ │ ├── ModemAddedEvent.java │ │ │ │ │ ├── ModemCdmaServiceProvider.java │ │ │ │ │ ├── ModemConfig.java │ │ │ │ │ ├── ModemConnectionStatus.java │ │ │ │ │ ├── ModemConnectionType.java │ │ │ │ │ ├── ModemDevice.java │ │ │ │ │ ├── ModemGpsDisabledEvent.java │ │ │ │ │ ├── ModemGpsEnabledEvent.java │ │ │ │ │ ├── ModemInterface.java │ │ │ │ │ ├── ModemInterfaceAddress.java │ │ │ │ │ ├── ModemInterfaceAddressConfig.java │ │ │ │ │ ├── ModemManagerService.java │ │ │ │ │ ├── ModemMonitorListener.java │ │ │ │ │ ├── ModemMonitorService.java │ │ │ │ │ ├── ModemPdpContext.java │ │ │ │ │ ├── ModemPdpContextType.java │ │ │ │ │ ├── ModemPowerMode.java │ │ │ │ │ ├── ModemReadyEvent.java │ │ │ │ │ ├── ModemRegistrationStatus.java │ │ │ │ │ ├── ModemRemovedEvent.java │ │ │ │ │ ├── ModemTechnologyType.java │ │ │ │ │ ├── SerialModemDevice.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── package-info.java │ │ │ │ ├── route/ │ │ │ │ │ ├── RouteConfig.java │ │ │ │ │ ├── RouteConfig4.java │ │ │ │ │ ├── RouteConfig6.java │ │ │ │ │ ├── RouteConfigIP.java │ │ │ │ │ ├── RouteConfigIP4.java │ │ │ │ │ ├── RouteConfigIP6.java │ │ │ │ │ ├── RoutingAgentService.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── status/ │ │ │ │ │ ├── NetworkInterfaceIpAddress.java │ │ │ │ │ ├── NetworkInterfaceIpAddressStatus.java │ │ │ │ │ ├── NetworkInterfaceState.java │ │ │ │ │ ├── NetworkInterfaceStatus.java │ │ │ │ │ ├── NetworkInterfaceType.java │ │ │ │ │ ├── NetworkStatusService.java │ │ │ │ │ ├── ethernet/ │ │ │ │ │ │ ├── EthernetInterfaceStatus.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ ├── loopback/ │ │ │ │ │ │ ├── LoopbackInterfaceStatus.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ ├── modem/ │ │ │ │ │ │ ├── AccessTechnology.java │ │ │ │ │ │ ├── Bearer.java │ │ │ │ │ │ ├── BearerIpType.java │ │ │ │ │ │ ├── ESimStatus.java │ │ │ │ │ │ ├── ModemBand.java │ │ │ │ │ │ ├── ModemCapability.java │ │ │ │ │ │ ├── ModemConnectionStatus.java │ │ │ │ │ │ ├── ModemGpsMode.java │ │ │ │ │ │ ├── ModemInterfaceStatus.java │ │ │ │ │ │ ├── ModemMode.java │ │ │ │ │ │ ├── ModemModePair.java │ │ │ │ │ │ ├── ModemPortType.java │ │ │ │ │ │ ├── ModemPowerState.java │ │ │ │ │ │ ├── RegistrationStatus.java │ │ │ │ │ │ ├── Sim.java │ │ │ │ │ │ ├── SimType.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ ├── package-info.java │ │ │ │ │ ├── vlan/ │ │ │ │ │ │ ├── VlanInterfaceStatus.java │ │ │ │ │ │ └── package-info.java │ │ │ │ │ └── wifi/ │ │ │ │ │ ├── WifiAccessPoint.java │ │ │ │ │ ├── WifiCapability.java │ │ │ │ │ ├── WifiChannel.java │ │ │ │ │ ├── WifiFlag.java │ │ │ │ │ ├── WifiInterfaceStatus.java │ │ │ │ │ ├── WifiMode.java │ │ │ │ │ ├── WifiRadioMode.java │ │ │ │ │ ├── WifiSecurity.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── vlan/ │ │ │ │ │ ├── VlanInterface.java │ │ │ │ │ └── package-info.java │ │ │ │ └── wifi/ │ │ │ │ ├── WifiAccessPoint.java │ │ │ │ ├── WifiAccessPointAddedEvent.java │ │ │ │ ├── WifiAccessPointRemovedEvent.java │ │ │ │ ├── WifiBgscan.java │ │ │ │ ├── WifiBgscanModule.java │ │ │ │ ├── WifiChannel.java │ │ │ │ ├── WifiCiphers.java │ │ │ │ ├── WifiClientMonitorListener.java │ │ │ │ ├── WifiClientMonitorService.java │ │ │ │ ├── WifiConfig.java │ │ │ │ ├── WifiHotspotInfo.java │ │ │ │ ├── WifiInterface.java │ │ │ │ ├── WifiInterfaceAddress.java │ │ │ │ ├── WifiInterfaceAddressConfig.java │ │ │ │ ├── WifiMode.java │ │ │ │ ├── WifiPassword.java │ │ │ │ ├── WifiRadioMode.java │ │ │ │ ├── WifiSecurity.java │ │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ ├── position/ │ │ │ │ ├── GNSSType.java │ │ │ │ ├── NmeaPosition.java │ │ │ │ ├── PositionException.java │ │ │ │ ├── PositionListener.java │ │ │ │ ├── PositionLockedEvent.java │ │ │ │ ├── PositionLostEvent.java │ │ │ │ ├── PositionService.java │ │ │ │ └── package-info.java │ │ │ ├── security/ │ │ │ │ ├── FloodingProtectionConfigurationChangeEvent.java │ │ │ │ ├── FloodingProtectionConfigurationService.java │ │ │ │ ├── SecurityService.java │ │ │ │ ├── ThreatManagerService.java │ │ │ │ ├── keystore/ │ │ │ │ │ ├── KeystoreChangedEvent.java │ │ │ │ │ ├── KeystoreInfo.java │ │ │ │ │ ├── KeystoreService.java │ │ │ │ │ └── package-info.java │ │ │ │ ├── package-info.java │ │ │ │ └── tamper/ │ │ │ │ └── detection/ │ │ │ │ ├── TamperDetectionProperties.java │ │ │ │ ├── TamperDetectionService.java │ │ │ │ ├── TamperEvent.java │ │ │ │ ├── TamperStatus.java │ │ │ │ └── package-info.java │ │ │ ├── ssl/ │ │ │ │ ├── SslManagerService.java │ │ │ │ ├── SslServiceListener.java │ │ │ │ └── package-info.java │ │ │ ├── status/ │ │ │ │ ├── CloudConnectionStatusComponent.java │ │ │ │ ├── CloudConnectionStatusEnum.java │ │ │ │ ├── CloudConnectionStatusService.java │ │ │ │ └── package-info.java │ │ │ ├── system/ │ │ │ │ ├── ExtendedProperties.java │ │ │ │ ├── ExtendedPropertyGroup.java │ │ │ │ ├── InternetConnectionStatus.java │ │ │ │ ├── SystemAdminService.java │ │ │ │ ├── SystemResourceInfo.java │ │ │ │ ├── SystemResourceType.java │ │ │ │ ├── SystemService.java │ │ │ │ └── package-info.java │ │ │ ├── type/ │ │ │ │ ├── BooleanValue.java │ │ │ │ ├── ByteArrayValue.java │ │ │ │ ├── DataType.java │ │ │ │ ├── DoubleValue.java │ │ │ │ ├── FloatValue.java │ │ │ │ ├── IntegerValue.java │ │ │ │ ├── LongValue.java │ │ │ │ ├── StringValue.java │ │ │ │ ├── TypedValue.java │ │ │ │ ├── TypedValues.java │ │ │ │ └── package-info.java │ │ │ ├── usb/ │ │ │ │ ├── AbstractUsbDevice.java │ │ │ │ ├── UsbBlockDevice.java │ │ │ │ ├── UsbDevice.java │ │ │ │ ├── UsbDeviceAddedEvent.java │ │ │ │ ├── UsbDeviceEvent.java │ │ │ │ ├── UsbDeviceRemovedEvent.java │ │ │ │ ├── UsbDeviceType.java │ │ │ │ ├── UsbModemDevice.java │ │ │ │ ├── UsbNetDevice.java │ │ │ │ ├── UsbService.java │ │ │ │ ├── UsbTtyDevice.java │ │ │ │ └── package-info.java │ │ │ ├── watchdog/ │ │ │ │ ├── CriticalComponent.java │ │ │ │ ├── WatchdogService.java │ │ │ │ └── package-info.java │ │ │ └── wire/ │ │ │ ├── WireComponent.java │ │ │ ├── WireConfiguration.java │ │ │ ├── WireEmitter.java │ │ │ ├── WireEnvelope.java │ │ │ ├── WireHelperService.java │ │ │ ├── WireReceiver.java │ │ │ ├── WireRecord.java │ │ │ ├── WireSupport.java │ │ │ ├── graph/ │ │ │ │ ├── BarrierAggregatorFactory.java │ │ │ │ ├── CachingAggregatorFactory.java │ │ │ │ ├── Constants.java │ │ │ │ ├── EmitterPort.java │ │ │ │ ├── MultiportWireConfiguration.java │ │ │ │ ├── MultiportWireSupport.java │ │ │ │ ├── Port.java │ │ │ │ ├── PortAggregator.java │ │ │ │ ├── PortAggregatorFactory.java │ │ │ │ ├── ReceiverPort.java │ │ │ │ ├── WireComponentConfiguration.java │ │ │ │ ├── WireComponentDefinition.java │ │ │ │ ├── WireComponentDefinitionService.java │ │ │ │ ├── WireGraphConfiguration.java │ │ │ │ ├── WireGraphService.java │ │ │ │ └── package-info.java │ │ │ ├── multiport/ │ │ │ │ ├── MultiportWireEmitter.java │ │ │ │ ├── MultiportWireReceiver.java │ │ │ │ └── package-info.java │ │ │ ├── package-info.java │ │ │ └── store/ │ │ │ └── provider/ │ │ │ ├── QueryableWireRecordStoreProvider.java │ │ │ ├── WireRecordStore.java │ │ │ ├── WireRecordStoreProvider.java │ │ │ └── package-info.java │ │ └── resources/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── messages/ │ │ └── KuraExceptionMessagesBundle.properties │ ├── org.eclipse.kura.camel/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ ├── MANIFEST.MF │ │ │ └── services/ │ │ │ └── org/ │ │ │ └── apache/ │ │ │ └── camel/ │ │ │ └── TypeConverter │ │ ├── OSGI-INF/ │ │ │ ├── kuraCloudResolver.properties │ │ │ └── kuraCloudResolver.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── camel/ │ │ ├── bean/ │ │ │ └── PayloadFactory.java │ │ ├── camelcloud/ │ │ │ ├── CamelCloudService.java │ │ │ ├── DefaultCamelCloudService.java │ │ │ ├── KuraCloudClientConstants.java │ │ │ └── package-info.java │ │ ├── cloud/ │ │ │ ├── KuraCloudComponent.java │ │ │ ├── KuraCloudComponentResolver.java │ │ │ ├── KuraCloudConstants.java │ │ │ ├── KuraCloudConsumer.java │ │ │ ├── KuraCloudEndpoint.java │ │ │ ├── KuraCloudProducer.java │ │ │ └── package-info.java │ │ ├── component/ │ │ │ ├── AbstractCamelComponent.java │ │ │ ├── AbstractJavaCamelComponent.java │ │ │ ├── AbstractXmlCamelComponent.java │ │ │ ├── Configuration.java │ │ │ └── package-info.java │ │ ├── internal/ │ │ │ ├── camelcloud/ │ │ │ │ └── CamelCloudClient.java │ │ │ ├── cloud/ │ │ │ │ ├── CloudClientCache.java │ │ │ │ └── CloudClientCacheImpl.java │ │ │ └── utils/ │ │ │ └── KuraServiceFactory.java │ │ ├── package-info.java │ │ ├── router/ │ │ │ ├── CamelRouter.java │ │ │ └── package-info.java │ │ ├── runner/ │ │ │ ├── AbstractRoutesProvider.java │ │ │ ├── BeforeStart.java │ │ │ ├── BuilderRoutesProvider.java │ │ │ ├── CamelRunner.java │ │ │ ├── ContextFactory.java │ │ │ ├── ContextLifecycleListener.java │ │ │ ├── DefaultServiceDependency.java │ │ │ ├── DependencyRunner.java │ │ │ ├── EmptyRoutesProvider.java │ │ │ ├── RegistryFactory.java │ │ │ ├── RoutesProvider.java │ │ │ ├── ScriptRunner.java │ │ │ ├── ServiceConsumer.java │ │ │ ├── ServiceDependency.java │ │ │ ├── SimpleRoutesProvider.java │ │ │ ├── XmlRoutesProvider.java │ │ │ └── package-info.java │ │ ├── type/ │ │ │ ├── TypeConverter.java │ │ │ └── package-info.java │ │ └── utils/ │ │ ├── CamelContexts.java │ │ └── package-info.java │ ├── org.eclipse.kura.camel.cloud.factory/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── factory.xml │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.camel.cloud.factory.CamelFactory.xml │ │ │ └── serviceFactory.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── camel/ │ │ └── cloud/ │ │ └── factory/ │ │ └── internal/ │ │ ├── CamelCloudServiceFactory.java │ │ ├── CamelFactory.java │ │ ├── ServiceConfiguration.java │ │ └── XmlCamelCloudService.java │ ├── org.eclipse.kura.camel.xml/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.camel.xml.XmlRouterComponent.xml │ │ │ └── xmlRouter.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── camel/ │ │ └── xml/ │ │ ├── XmlRouterComponent.java │ │ └── package-info.java │ ├── org.eclipse.kura.cloud.base.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── data.xml │ │ │ ├── metatype/ │ │ │ │ ├── org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport.xml │ │ │ │ └── org.eclipse.kura.data.DataService.xml │ │ │ └── mqttDataTransport.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── lib/ │ │ │ └── org.eclipse.paho.client.mqttv3-1.2.1.k2.jar │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ ├── data/ │ │ │ ├── AlwaysConnectedStrategy.java │ │ │ ├── AutoConnectStrategy.java │ │ │ ├── DataMessage.java │ │ │ ├── DataServiceImpl.java │ │ │ ├── DataServiceListenerS.java │ │ │ ├── DataServiceOptions.java │ │ │ ├── DataStore.java │ │ │ ├── ScheduleStrategy.java │ │ │ ├── store/ │ │ │ │ ├── HouseKeeperTask.java │ │ │ │ └── MessageStoreState.java │ │ │ ├── transport/ │ │ │ │ └── mqtt/ │ │ │ │ ├── DataTransportListenerS.java │ │ │ │ ├── MqttClientConfiguration.java │ │ │ │ └── MqttDataTransport.java │ │ │ └── util/ │ │ │ └── MqttTopicUtil.java │ │ └── internal/ │ │ └── data/ │ │ └── TokenBucket.java │ ├── org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── cloud.xml │ │ │ ├── cloudConnectionFactory.xml │ │ │ ├── cloudPublisher.xml │ │ │ └── metatype/ │ │ │ ├── org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher.xml │ │ │ └── org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── cloudconnection/ │ │ │ └── eclipseiot/ │ │ │ └── mqtt/ │ │ │ ├── cloud/ │ │ │ │ ├── CloudConnectionManagerImpl.java │ │ │ │ ├── CloudConnectionManagerOptions.java │ │ │ │ ├── CloudPayloadEncoder.java │ │ │ │ ├── CloudPayloadGZipEncoder.java │ │ │ │ ├── CloudPayloadProtoBufDecoderImpl.java │ │ │ │ ├── CloudPayloadProtoBufEncoderImpl.java │ │ │ │ ├── CloudPublisherDeliveryListener.java │ │ │ │ ├── CloudServiceLifecycleCertsPolicy.java │ │ │ │ ├── CloudSubscriptionRecord.java │ │ │ │ ├── ControlTopic.java │ │ │ │ ├── LifeCyclePayloadBuilder.java │ │ │ │ ├── LifecycleMessage.java │ │ │ │ ├── MessageHandlerCallable.java │ │ │ │ ├── factory/ │ │ │ │ │ └── DefaultCloudConnectionFactory.java │ │ │ │ └── publisher/ │ │ │ │ ├── CloudPublisherImpl.java │ │ │ │ └── CloudPublisherOptions.java │ │ │ └── message/ │ │ │ ├── MessageConstants.java │ │ │ ├── MessageType.java │ │ │ └── protobuf/ │ │ │ └── KuraPayloadProto.java │ │ └── protobuf/ │ │ └── kurapayload.proto │ ├── org.eclipse.kura.cloudconnection.kapua.mqtt.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── cloud.xml │ │ │ ├── cloudCall.xml │ │ │ ├── cloudPublisher.xml │ │ │ ├── cloudSubscriber.xml │ │ │ └── metatype/ │ │ │ ├── org.eclipse.kura.cloud.CloudService.xml │ │ │ ├── org.eclipse.kura.cloud.publisher.CloudPublisher.xml │ │ │ └── org.eclipse.kura.cloud.subscriber.CloudSubscriber.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ ├── cloud/ │ │ │ │ └── app/ │ │ │ │ └── RequestIdGenerator.java │ │ │ └── core/ │ │ │ ├── cloud/ │ │ │ │ ├── CloudClientImpl.java │ │ │ │ ├── CloudClientListenerAdapter.java │ │ │ │ ├── CloudPayloadEncoder.java │ │ │ │ ├── CloudPayloadGZipEncoder.java │ │ │ │ ├── CloudPayloadProtoBufDecoderImpl.java │ │ │ │ ├── CloudPayloadProtoBufEncoderImpl.java │ │ │ │ ├── CloudPublisherDeliveryListener.java │ │ │ │ ├── CloudServiceImpl.java │ │ │ │ ├── CloudServiceOptions.java │ │ │ │ ├── KuraTopicImpl.java │ │ │ │ ├── LifeCyclePayloadBuilder.java │ │ │ │ ├── LifecycleMessage.java │ │ │ │ ├── MessageHandlerCallable.java │ │ │ │ ├── call/ │ │ │ │ │ └── CloudCallServiceImpl.java │ │ │ │ ├── publisher/ │ │ │ │ │ ├── CloudPublisherImpl.java │ │ │ │ │ ├── CloudPublisherOptions.java │ │ │ │ │ └── NotificationPublisherImpl.java │ │ │ │ └── subscriber/ │ │ │ │ ├── CloudSubscriberImpl.java │ │ │ │ ├── CloudSubscriberOptions.java │ │ │ │ └── CloudSubscriptionRecord.java │ │ │ └── message/ │ │ │ ├── MessageConstants.java │ │ │ ├── MessageType.java │ │ │ └── protobuf/ │ │ │ └── KuraPayloadProto.java │ │ └── protobuf/ │ │ └── kurapayload.proto │ ├── org.eclipse.kura.cloudconnection.raw.mqtt.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── cloud.xml │ │ │ ├── cloudPublisher.xml │ │ │ ├── cloudServiceFactory.xml │ │ │ ├── cloudSubscriber.xml │ │ │ └── metatype/ │ │ │ ├── org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint.xml │ │ │ ├── org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher.xml │ │ │ └── org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ ├── cloudconnection/ │ │ │ └── raw/ │ │ │ └── mqtt/ │ │ │ ├── cloud/ │ │ │ │ ├── Constants.java │ │ │ │ ├── Qos.java │ │ │ │ └── RawMqttCloudEndpoint.java │ │ │ ├── factory/ │ │ │ │ └── RawMqttCloudConnectionFactory.java │ │ │ ├── publisher/ │ │ │ │ ├── PublishOptions.java │ │ │ │ └── RawMqttPublisher.java │ │ │ └── subscriber/ │ │ │ ├── RawMqttSubscriber.java │ │ │ └── SubscribeOptions.java │ │ └── cloudconnecton/ │ │ └── raw/ │ │ └── mqtt/ │ │ └── util/ │ │ ├── AbstractStackComponent.java │ │ ├── Property.java │ │ ├── StackComponentOptions.java │ │ └── Utils.java │ ├── org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── SparkplugCloudConnectionFactory.xml │ │ │ ├── SparkplugCloudEndpoint.xml │ │ │ ├── SparkplugDataTransport.xml │ │ │ ├── SparkplugDevice.xml │ │ │ ├── SparkplugSubscriber.xml │ │ │ └── metatype/ │ │ │ ├── org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice.xml │ │ │ ├── org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint.xml │ │ │ ├── org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber.xml │ │ │ └── org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── lib/ │ │ │ └── org.eclipse.paho.client.mqttv3-1.2.1.k2.jar │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── cloudconnection/ │ │ │ └── sparkplug/ │ │ │ └── mqtt/ │ │ │ ├── device/ │ │ │ │ └── SparkplugDevice.java │ │ │ ├── endpoint/ │ │ │ │ ├── SeqCounter.java │ │ │ │ ├── SparkplugCloudEndpoint.java │ │ │ │ ├── SubscriptionRecord.java │ │ │ │ └── SubscriptionsMap.java │ │ │ ├── factory/ │ │ │ │ └── SparkplugCloudConnectionFactory.java │ │ │ ├── message/ │ │ │ │ ├── SparkplugBProtobufPayloadBuilder.java │ │ │ │ ├── SparkplugMessageType.java │ │ │ │ ├── SparkplugPayloads.java │ │ │ │ └── SparkplugTopics.java │ │ │ ├── subscriber/ │ │ │ │ └── SparkplugSubscriber.java │ │ │ ├── transport/ │ │ │ │ ├── BdSeqCounter.java │ │ │ │ ├── SparkplugDataTransport.java │ │ │ │ ├── SparkplugDataTransportOptions.java │ │ │ │ └── SparkplugMqttClient.java │ │ │ └── utils/ │ │ │ ├── InvocationUtils.java │ │ │ └── SparkplugCloudEndpointTracker.java │ │ └── proto/ │ │ └── sparkplug_b.proto │ ├── org.eclipse.kura.configuration.change.manager/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml │ │ │ └── org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── configuration/ │ │ └── change/ │ │ └── manager/ │ │ ├── ComponentsServiceTracker.java │ │ ├── ConfigurationChangeManager.java │ │ ├── ConfigurationChangeManagerOptions.java │ │ └── ServiceTrackerListener.java │ ├── org.eclipse.kura.container.orchestration.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── component.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── container/ │ │ └── orchestration/ │ │ └── provider/ │ │ └── impl/ │ │ ├── ContainerOrchestrationServiceImpl.java │ │ ├── ContainerOrchestrationServiceOptions.java │ │ └── enforcement/ │ │ └── AllowlistEnforcementMonitor.java │ ├── org.eclipse.kura.container.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── containerinstance.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.container.provider.ContainerInstance.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── container/ │ │ └── provider/ │ │ ├── ContainerInstance.java │ │ ├── ContainerInstanceOptions.java │ │ └── PasswordGenerator.java │ ├── org.eclipse.kura.core/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ ├── internal/ │ │ │ └── linux/ │ │ │ └── executor/ │ │ │ ├── ExecutorUtil.java │ │ │ ├── FlushPumpStreamHandler.java │ │ │ └── FlushStreamPumper.java │ │ ├── linux/ │ │ │ ├── executor/ │ │ │ │ ├── LinuxExitStatus.java │ │ │ │ ├── LinuxPid.java │ │ │ │ ├── LinuxResultHandler.java │ │ │ │ ├── LinuxSignal.java │ │ │ │ ├── privileged/ │ │ │ │ │ └── PrivilegedExecutorServiceImpl.java │ │ │ │ └── unprivileged/ │ │ │ │ └── UnprivilegedExecutorServiceImpl.java │ │ │ └── util/ │ │ │ ├── LinuxProcessUtil.java │ │ │ └── ProcessStats.java │ │ ├── ssl/ │ │ │ ├── ConnectionSslOptions.java │ │ │ ├── SSLContextSPIWrapper.java │ │ │ ├── SSLSocketFactoryWrapper.java │ │ │ ├── SslManagerServiceImpl.java │ │ │ ├── SslManagerServiceOCD.java │ │ │ ├── SslManagerServiceOptions.java │ │ │ └── SslServiceListeners.java │ │ ├── util/ │ │ │ ├── GZipUtil.java │ │ │ ├── IOUtil.java │ │ │ ├── NamedThreadFactory.java │ │ │ ├── NetUtil.java │ │ │ ├── ProcessUtil.java │ │ │ ├── QuickSort.java │ │ │ ├── SafeProcess.java │ │ │ ├── ThrowableUtil.java │ │ │ └── ValidationUtil.java │ │ └── watchdog/ │ │ └── CriticalServiceImpl.java │ ├── org.eclipse.kura.core.certificates/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── CertificatesService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── certificates/ │ │ ├── CertificatesManager.java │ │ └── KeyStoreManagement.java │ ├── org.eclipse.kura.core.cloud.factory/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── cloudServiceFactory.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── cloud/ │ │ └── factory/ │ │ └── DefaultCloudServiceFactory.java │ ├── org.eclipse.kura.core.comm/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── comm.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── comm/ │ │ ├── CommConnectionFactory.java │ │ └── CommConnectionImpl.java │ ├── org.eclipse.kura.core.configuration/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── cloudConfigurationHandler.xml │ │ │ └── configuration.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── configuration/ │ │ ├── CloudConfigurationHandler.java │ │ ├── ComponentConfigurationImpl.java │ │ ├── ComponentMetaTypeBundleTracker.java │ │ ├── ConfigurableComponentTracker.java │ │ ├── ConfigurationChangeEvent.java │ │ ├── ConfigurationServiceAuditFacade.java │ │ ├── ConfigurationServiceImpl.java │ │ ├── Password.java │ │ ├── XmlComponentConfigurations.java │ │ ├── XmlConfigPropertiesAdapted.java │ │ ├── XmlConfigPropertiesAdapter.java │ │ ├── XmlConfigPropertyAdapted.java │ │ ├── XmlSnapshotIdResult.java │ │ ├── metatype/ │ │ │ ├── ObjectFactory.java │ │ │ ├── Tad.java │ │ │ ├── Tattribute.java │ │ │ ├── Tdesignate.java │ │ │ ├── Ticon.java │ │ │ ├── Tmetadata.java │ │ │ ├── Tobject.java │ │ │ ├── Tocd.java │ │ │ ├── Toption.java │ │ │ ├── Tscalar.java │ │ │ └── package-info.java │ │ ├── package-info.java │ │ ├── upgrade/ │ │ │ ├── ConfigurationUpgrade.java │ │ │ └── WireAssetConfigurationUpgrade.java │ │ └── util/ │ │ ├── CollectionsUtil.java │ │ ├── ComponentUtil.java │ │ └── StringUtil.java │ ├── org.eclipse.kura.core.crypto/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── crypto.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── crypto/ │ │ ├── CryptoServiceImpl.java │ │ └── SystemdCredentialLoader.java │ ├── org.eclipse.kura.core.identity/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── org.eclipse.kura.core.identity.IdentityServiceImpl.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── identity/ │ │ ├── IdentityServiceImpl.java │ │ ├── LoginBannerServiceImpl.java │ │ ├── LoginBannerServiceOptions.java │ │ ├── PasswordHashImpl.java │ │ ├── PasswordHasher.java │ │ ├── PasswordStrengthVerificationServiceImpl.java │ │ ├── PasswordStrengthVerificationServiceOptions.java │ │ ├── ValidationUtil.java │ │ └── store/ │ │ ├── IdentityStore.java │ │ ├── TemporaryIdentityStore.java │ │ ├── TemporaryIdentityStoreAdapter.java │ │ └── UserAdminIdentityStore.java │ ├── org.eclipse.kura.core.inventory/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── inventory.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── inventory/ │ │ ├── InventoryHandlerV1.java │ │ └── resources/ │ │ ├── ContainerImage.java │ │ ├── ContainerImages.java │ │ ├── DockerContainer.java │ │ ├── DockerContainers.java │ │ ├── SystemBundle.java │ │ ├── SystemBundleRef.java │ │ ├── SystemBundles.java │ │ ├── SystemDeploymentPackage.java │ │ ├── SystemDeploymentPackages.java │ │ ├── SystemPackage.java │ │ ├── SystemPackages.java │ │ └── SystemResourcesInfo.java │ ├── org.eclipse.kura.core.keystore/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ ├── org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl.xml │ │ │ │ └── org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl.xml │ │ │ ├── org.eclipse.kura.core.keystore.keystoreService.xml │ │ │ └── org.eclipse.kura.core.keystore.pkcs11KeystoreService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── keystore/ │ │ ├── BaseKeystoreService.java │ │ ├── FilesystemKeystoreServiceImpl.java │ │ ├── FilesystemKeystoreServiceOptions.java │ │ ├── KeystoreInstance.java │ │ ├── PKCS11KeystoreServiceImpl.java │ │ ├── PKCS11KeystoreServiceOptions.java │ │ ├── crl/ │ │ │ ├── CRLManager.java │ │ │ ├── CRLManagerOptions.java │ │ │ ├── CRLStore.java │ │ │ └── StoredCRL.java │ │ └── util/ │ │ ├── CRLUtil.java │ │ ├── CertificateInfo.java │ │ ├── CertificateUtil.java │ │ ├── CsrInfo.java │ │ ├── EntryInfo.java │ │ ├── EntryType.java │ │ ├── KeyPairInfo.java │ │ ├── KeystoreUtils.java │ │ ├── MappingCollection.java │ │ └── PrivateKeyInfo.java │ ├── org.eclipse.kura.core.status/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── status.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── status/ │ │ ├── CloudConnectionStatusServiceImpl.java │ │ ├── CloudConnectionStatusURL.java │ │ ├── GpioLedManager.java │ │ ├── IdleStatusComponent.java │ │ ├── LedManager.java │ │ ├── LinuxLedManager.java │ │ ├── StatusNotificationTypeEnum.java │ │ └── runnables/ │ │ ├── BlinkStatusRunnable.java │ │ ├── HeartbeatStatusRunnable.java │ │ ├── LogStatusRunnable.java │ │ ├── OnOffStatusRunnable.java │ │ └── StatusRunnable.java │ ├── org.eclipse.kura.core.system/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── system.xml │ │ │ └── systemAdmin.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── core/ │ │ └── system/ │ │ ├── SuperSystemService.java │ │ ├── SystemAdminServiceImpl.java │ │ └── SystemServiceImpl.java │ ├── org.eclipse.kura.db.h2db.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── h2db.xml │ │ │ ├── h2dbserver.xml │ │ │ └── metatype/ │ │ │ ├── org.eclipse.kura.core.db.H2DbServer.xml │ │ │ └── org.eclipse.kura.core.db.H2DbService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── db/ │ │ └── h2db/ │ │ └── provider/ │ │ ├── H2DbMessageStoreImpl.java │ │ ├── H2DbQueryableWireRecordStoreImpl.java │ │ ├── H2DbServer.java │ │ ├── H2DbServerOptions.java │ │ ├── H2DbServiceImpl.java │ │ ├── H2DbServiceOptions.java │ │ └── H2DbWireRecordStoreImpl.java │ ├── org.eclipse.kura.db.sqlite.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.db.SQLiteDbService.xml │ │ │ ├── org.eclipse.kura.db.SQLiteDbService.xml │ │ │ └── org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── db/ │ │ └── sqlite/ │ │ └── provider/ │ │ ├── ConnectionPoolManager.java │ │ ├── DatabaseLoader.java │ │ ├── SqliteDbServiceImpl.java │ │ ├── SqliteDbServiceOptions.java │ │ ├── SqliteDebugShell.java │ │ ├── SqliteMessageStoreImpl.java │ │ ├── SqliteProviderActivator.java │ │ ├── SqliteQueryableWireRecordStoreImpl.java │ │ ├── SqliteUtil.java │ │ └── SqliteWireRecordStoreImpl.java │ ├── org.eclipse.kura.docs/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ └── pom.xml │ ├── org.eclipse.kura.driver.block/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── driver/ │ │ ├── binary/ │ │ │ ├── AbstractBinaryData.java │ │ │ ├── BinaryData.java │ │ │ ├── BinaryDataTypes.java │ │ │ ├── Buffer.java │ │ │ ├── ByteArray.java │ │ │ ├── ByteArrayBuffer.java │ │ │ ├── Double.java │ │ │ ├── Endianness.java │ │ │ ├── Float.java │ │ │ ├── Int16.java │ │ │ ├── Int32.java │ │ │ ├── Int64.java │ │ │ ├── Int8.java │ │ │ ├── TypeUtil.java │ │ │ ├── UInt16.java │ │ │ ├── UInt32.java │ │ │ ├── UInt8.java │ │ │ ├── UnsignedIntegerLE.java │ │ │ └── adapter/ │ │ │ ├── GainOffset.java │ │ │ ├── StringData.java │ │ │ └── ToBoolean.java │ │ └── block/ │ │ ├── Block.java │ │ ├── BlockAggregator.java │ │ ├── BlockFactory.java │ │ ├── ProhibitedBlock.java │ │ └── task/ │ │ ├── AbstractBlockDriver.java │ │ ├── BinaryDataTask.java │ │ ├── BitTask.java │ │ ├── BlockTask.java │ │ ├── BlockTaskAggregator.java │ │ ├── ByteArrayTask.java │ │ ├── ChannelBlockTask.java │ │ ├── ChannelBlockTaskWrapper.java │ │ ├── ChannelListenerBlockTask.java │ │ ├── Mode.java │ │ ├── StringTask.java │ │ ├── ToplevelBlockTask.java │ │ ├── UpdateBlockTask.java │ │ └── UpdateBlockTaskAggregator.java │ ├── org.eclipse.kura.driver.helper.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── DriverDescriptorComponent.xml │ │ │ └── DriverServiceComponent.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── driver/ │ │ ├── DriverDescriptorServiceImpl.java │ │ └── DriverServiceImpl.java │ ├── org.eclipse.kura.driver.s7plc.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── S7PlcDriverComponent.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.driver.s7plc.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── lib/ │ │ │ └── .gitignore │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── driver/ │ │ └── s7plc/ │ │ ├── S7PlcChannelDescriptor.java │ │ ├── S7PlcDataType.java │ │ ├── S7PlcDomain.java │ │ ├── S7PlcDriver.java │ │ ├── S7PlcOptions.java │ │ └── task/ │ │ ├── S7PlcTaskBuilder.java │ │ └── S7PlcToplevelBlockTask.java │ ├── org.eclipse.kura.event.publisher/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.event.publisher.EventPublisher.xml │ │ │ └── org.eclipse.kura.event.publisher.EventPublisher.xml │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── event/ │ │ └── publisher/ │ │ ├── EventPublisher.java │ │ ├── EventPublisherConstants.java │ │ ├── EventPublisherOptions.java │ │ └── helper/ │ │ ├── CloudEndpointServiceHelper.java │ │ ├── CloudEndpointServiceTracker.java │ │ └── CloudEndpointTrackerListener.java │ ├── org.eclipse.kura.http.server.manager/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── httpService.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.http.server.manager.HttpService.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── http/ │ │ └── server/ │ │ └── manager/ │ │ ├── BaseSslContextFactory.java │ │ ├── ClientAuthSslContextFactoryImpl.java │ │ ├── HttpService.java │ │ ├── HttpServiceOptions.java │ │ ├── JettyServerHolder.java │ │ └── KuraErrorHandler.java │ ├── org.eclipse.kura.json.marshaller.unmarshaller.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── JsonMarshallerUnmarshallerComponent.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── json/ │ │ └── marshaller/ │ │ └── unmarshaller/ │ │ ├── JsonMarshallUnmarshallImpl.java │ │ ├── keystore/ │ │ │ └── KeystoreEntryInfoMapper.java │ │ ├── message/ │ │ │ ├── CloudPayloadJsonDecoder.java │ │ │ ├── CloudPayloadJsonEncoder.java │ │ │ └── CloudPayloadJsonFields.java │ │ ├── system/ │ │ │ ├── JsonJavaContainerImagesMapper.java │ │ │ ├── JsonJavaDockerContainersMapper.java │ │ │ ├── JsonJavaSystemBundleRefMapper.java │ │ │ ├── JsonJavaSystemBundlesMapper.java │ │ │ ├── JsonJavaSystemDeploymentPackagesMapper.java │ │ │ ├── JsonJavaSystemPackagesMapper.java │ │ │ └── JsonJavaSystemResourcesMapper.java │ │ └── wiregraph/ │ │ └── WireGraphJsonMarshallUnmarshallImpl.java │ ├── org.eclipse.kura.jul.to.slf4j.configuration/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── jul/ │ │ └── to/ │ │ └── slf4j/ │ │ └── configuration/ │ │ └── Activator.java │ ├── org.eclipse.kura.linux.clock/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── clock.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.clock.ClockService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── linux/ │ │ └── clock/ │ │ ├── AbstractNtpClockSyncProvider.java │ │ ├── ChronyClockSyncProvider.java │ │ ├── ClockProviderType.java │ │ ├── ClockServiceConfig.java │ │ ├── ClockServiceImpl.java │ │ ├── ClockSyncListener.java │ │ ├── ClockSyncProvider.java │ │ └── JavaNtpClockSyncProvider.java │ ├── org.eclipse.kura.linux.usb/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── usb.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── c/ │ │ │ └── udev/ │ │ │ ├── .gitignore │ │ │ ├── LinuxUdev.c │ │ │ ├── LinuxUdev.h │ │ │ ├── Makefile │ │ │ ├── Makefile.aarch64 │ │ │ ├── Makefile.poky.arm_hf │ │ │ ├── Makefile.poky.arm_sf │ │ │ ├── Makefile.poky.i586 │ │ │ ├── Makefile.poky.x86_64 │ │ │ └── org_eclipse_kura_linux_usb_LinuxUdevNative.h │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── linux/ │ │ └── usb/ │ │ ├── LinuxUdevNative.java │ │ ├── UsbSerial.java │ │ ├── UsbSerialEntry.java │ │ └── UsbServiceImpl.java │ ├── org.eclipse.kura.linux.usb.aarch64/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ └── pom.xml │ ├── org.eclipse.kura.linux.usb.x86_64/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ └── pom.xml │ ├── org.eclipse.kura.linux.watchdog/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.watchdog.WatchdogService.xml │ │ │ └── watchdog.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── linux/ │ │ └── watchdog/ │ │ ├── CriticalComponentRegistration.java │ │ ├── RebootCauseFileWriter.java │ │ ├── WatchdogServiceImpl.java │ │ └── WatchdogServiceOptions.java │ ├── org.eclipse.kura.log.filesystem.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── FilesystemLogProvider.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── log/ │ │ └── filesystem/ │ │ └── provider/ │ │ ├── FilesystemLogProvider.java │ │ └── KuraLogLineParser.java │ ├── org.eclipse.kura.misc.cloudcat/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── CloudCat.xml │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.misc.cloudcat.CloudCat.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── misc/ │ │ └── cloudcat/ │ │ ├── CloudCat.java │ │ ├── CloudCatOptions.java │ │ ├── CloudCatSubscription.java │ │ └── CloudClientRelay.java │ ├── org.eclipse.kura.protocol.modbus/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── modbusProtocolDevice.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── protocol/ │ │ │ └── modbus/ │ │ │ ├── Crc16.java │ │ │ ├── ModbusCommEvent.java │ │ │ ├── ModbusDataOrder.java │ │ │ ├── ModbusFunctionCodes.java │ │ │ ├── ModbusProtocolDevice.java │ │ │ ├── ModbusProtocolDeviceService.java │ │ │ ├── ModbusProtocolErrorCode.java │ │ │ ├── ModbusProtocolException.java │ │ │ ├── ModbusTransmissionMode.java │ │ │ └── ProtocolPrimitiveDataTypes.java │ │ └── resources/ │ │ └── org.eclipse.kura.protocol.modbus.dpp │ ├── org.eclipse.kura.request.handler.jaxrs/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── request/ │ │ └── handler/ │ │ └── jaxrs/ │ │ ├── DefaultExceptionHandler.java │ │ ├── JaxRsRequestHandlerProxy.java │ │ ├── RequestParameterHandlers.java │ │ ├── ResponseBodyHandlers.java │ │ ├── annotation/ │ │ │ └── EXEC.java │ │ └── consumer/ │ │ ├── RequestArgumentHandler.java │ │ ├── RequestParameterHandler.java │ │ └── ResponseBodyHandler.java │ ├── org.eclipse.kura.rest.cloudconnection.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── CloudConnectionRestService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── cloudconnection/ │ │ └── provider/ │ │ ├── CloudConnectionManagerBridge.java │ │ ├── CloudConnectionRestService.java │ │ ├── CloudConnectionService.java │ │ ├── dto/ │ │ │ ├── CloudComponentFactories.java │ │ │ ├── CloudComponentInstances.java │ │ │ ├── CloudConnectionFactoryInfo.java │ │ │ ├── CloudConnectionFactoryPidAndCloudEndpointPid.java │ │ │ ├── CloudConnectionState.java │ │ │ ├── CloudEndpointInstance.java │ │ │ ├── CloudEndpointPidRequest.java │ │ │ ├── CloudEndpointType.java │ │ │ ├── CloudPubSubType.java │ │ │ ├── ConnectedStatus.java │ │ │ ├── PidAndFactoryPidAndCloudEndpointPid.java │ │ │ ├── PubSubFactoryInfo.java │ │ │ └── PubSubInstance.java │ │ └── util/ │ │ └── PidUtils.java │ ├── org.eclipse.kura.rest.configuration.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── configuration_rest_service.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ ├── internal/ │ │ │ └── rest/ │ │ │ └── configuration/ │ │ │ └── ConfigurationRestService.java │ │ └── rest/ │ │ └── configuration/ │ │ └── api/ │ │ ├── AdDTO.java │ │ ├── ComponentConfigurationDTO.java │ │ ├── ComponentConfigurationList.java │ │ ├── CreateFactoryComponentConfigurationsRequest.java │ │ ├── DTOUtil.java │ │ ├── DeleteFactoryComponentRequest.java │ │ ├── FactoryComponentConfigurationDTO.java │ │ ├── Failure.java │ │ ├── FailureHandler.java │ │ ├── IconDTO.java │ │ ├── OcdDTO.java │ │ ├── OptionDTO.java │ │ ├── PidAndFactoryPid.java │ │ ├── PidAndFactoryPidSet.java │ │ ├── PidSet.java │ │ ├── PropertyDTO.java │ │ ├── SnapshotId.java │ │ ├── SnapshotIdSet.java │ │ ├── SubtaskFailure.java │ │ ├── SubtaskFailureList.java │ │ ├── UpdateComponentConfigurationRequest.java │ │ └── Validable.java │ ├── org.eclipse.kura.rest.identity.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── identity/ │ │ └── provider/ │ │ ├── IdentityRestServiceV1.java │ │ ├── IdentityRestServiceV2.java │ │ ├── LegacyIdentityService.java │ │ ├── dto/ │ │ │ ├── PermissionDTO.java │ │ │ ├── UserConfigDTO.java │ │ │ ├── UserDTO.java │ │ │ └── ValidatorOptionsDTO.java │ │ ├── util/ │ │ │ ├── IdentityDTOUtils.java │ │ │ └── StringUtils.java │ │ └── v2/ │ │ └── dto/ │ │ ├── AdditionalConfigurationsDTO.java │ │ ├── IdentityConfigurationDTO.java │ │ ├── IdentityConfigurationRequestDTO.java │ │ ├── IdentityDTO.java │ │ ├── PasswordConfigurationDTO.java │ │ ├── PasswordStrenghtRequirementsDTO.java │ │ ├── PermissionConfigurationDTO.java │ │ └── PermissionDTO.java │ ├── org.eclipse.kura.rest.inventory.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── inventory_rest_service.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── inventory/ │ │ └── InventoryRestService.java │ ├── org.eclipse.kura.rest.keystore.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV1.xml │ │ │ ├── org.eclipse.kura.internal.rest.keystore.provider.KeystoreRestServiceV2.xml │ │ │ ├── org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV1.xml │ │ │ └── org.eclipse.kura.internal.rest.keystore.request.handler.KeystoreServiceRequestHandlerV2.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── keystore/ │ │ ├── provider/ │ │ │ ├── CsrResponse.java │ │ │ ├── KeystoreRestService.java │ │ │ ├── KeystoreRestServiceV1.java │ │ │ └── KeystoreRestServiceV2.java │ │ ├── request/ │ │ │ ├── CsrReadRequest.java │ │ │ ├── EntryRequest.java │ │ │ ├── KeyPairWriteRequest.java │ │ │ ├── PrivateKeyWriteRequest.java │ │ │ ├── TrustedCertificateWriteRequest.java │ │ │ └── handler/ │ │ │ ├── KeystoreServiceRequestHandler.java │ │ │ ├── KeystoreServiceRequestHandlerV1.java │ │ │ └── KeystoreServiceRequestHandlerV2.java │ │ └── util/ │ │ └── KeystoreRemoteService.java │ ├── org.eclipse.kura.rest.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── metatype/ │ │ │ └── org.eclipse.kura.internal.rest.provider.RestService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ ├── internal/ │ │ │ └── rest/ │ │ │ ├── auth/ │ │ │ │ ├── BasicAuthenticationProvider.java │ │ │ │ ├── CertificateAuthenticationProvider.java │ │ │ │ ├── ConfigurationAdminHelper.java │ │ │ │ ├── RestIdentityHelper.java │ │ │ │ ├── RestSessionHelper.java │ │ │ │ ├── SessionAttributes.java │ │ │ │ ├── SessionAuthProvider.java │ │ │ │ ├── SessionRestService.java │ │ │ │ ├── SessionRestServiceConstants.java │ │ │ │ └── dto/ │ │ │ │ ├── AuthenticationInfoDTO.java │ │ │ │ ├── AuthenticationResponseDTO.java │ │ │ │ ├── IdentityInfoDTO.java │ │ │ │ ├── UpdatePasswordDTO.java │ │ │ │ ├── UsernamePasswordDTO.java │ │ │ │ └── XsrfTokenDTO.java │ │ │ └── provider/ │ │ │ ├── AuditFilter.java │ │ │ ├── AuthenticationFilter.java │ │ │ ├── AuthenticationProviderHolder.java │ │ │ ├── AuthorizationFilter.java │ │ │ ├── GsonSerializer.java │ │ │ ├── IncomingPortCheckFilter.java │ │ │ ├── RestService.java │ │ │ ├── RestServiceOptions.java │ │ │ └── RestServiceUtils.java │ │ └── rest/ │ │ ├── auth/ │ │ │ └── AuthenticationProvider.java │ │ └── utils/ │ │ ├── Validable.java │ │ └── package-info.java │ ├── org.eclipse.kura.rest.security.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── SecurityRestServiceV1.xml │ │ │ └── SecurityRestServiceV2.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── security/ │ │ └── provider/ │ │ ├── AbstractRestSecurityService.java │ │ ├── SecurityRestServiceV1.java │ │ ├── SecurityRestServiceV2.java │ │ └── dto/ │ │ └── DebugEnabledDTO.java │ ├── org.eclipse.kura.rest.service.listing.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── ServiceListingRestService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── rest/ │ │ └── service/ │ │ └── listing/ │ │ └── provider/ │ │ ├── RestServiceListingProvider.java │ │ ├── dto/ │ │ │ ├── FilterDTO.java │ │ │ ├── InterfaceNamesDTO.java │ │ │ └── RefDTO.java │ │ └── util/ │ │ └── FilterBuilder.java │ ├── org.eclipse.kura.rest.system.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── SystemRestService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── rest/ │ │ └── system/ │ │ ├── Constants.java │ │ ├── SystemRestService.java │ │ └── dto/ │ │ ├── ExtendedPropertiesDTO.java │ │ ├── FilterDTO.java │ │ ├── FrameworkPropertiesDTO.java │ │ └── KuraPropertiesDTO.java │ ├── org.eclipse.kura.rest.tamper.detection.provider/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRequestHandler.xml │ │ │ └── org.eclipse.kura.rest.tamper.detection.provider.TamperDetectionRestService.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ ├── internal/ │ │ │ └── rest/ │ │ │ └── tamper/ │ │ │ └── detection/ │ │ │ ├── TamperDetectionRequestHandler.java │ │ │ ├── TamperDetectionRestService.java │ │ │ └── util/ │ │ │ └── TamperDetectionRemoteService.java │ │ └── rest/ │ │ └── tamper/ │ │ └── detection/ │ │ └── api/ │ │ ├── TamperDetectionServiceInfo.java │ │ └── TamperStatusInfo.java │ ├── org.eclipse.kura.stress/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.stress.Stress.xml │ │ │ └── stress.xml │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v20.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── stress/ │ │ │ └── HeapStress.java │ │ └── resources/ │ │ ├── stress.dp │ │ └── stress.dpp │ ├── org.eclipse.kura.useradmin.store/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ └── org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl.xml │ │ │ └── org.eclipse.kura.internal.useradmin.store.RoleRepositoryStoreImpl.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── useradmin/ │ │ └── store/ │ │ ├── DeserializationException.java │ │ ├── RoleRepositoryStoreImpl.java │ │ ├── RoleRepositoryStoreOptions.java │ │ └── RoleSerializer.java │ ├── org.eclipse.kura.util/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── util/ │ │ ├── base/ │ │ │ ├── StringUtil.java │ │ │ └── TypeUtil.java │ │ ├── collection/ │ │ │ └── CollectionUtil.java │ │ ├── configuration/ │ │ │ └── Property.java │ │ ├── jdbc/ │ │ │ ├── ConnectionProvider.java │ │ │ ├── JdbcUtil.java │ │ │ ├── SQLBiFunction.java │ │ │ ├── SQLFunction.java │ │ │ └── SQLSupplier.java │ │ ├── message/ │ │ │ └── store/ │ │ │ ├── AbstractJdbcMessageStoreImpl.java │ │ │ └── JdbcMessageStoreQueries.java │ │ ├── osgi/ │ │ │ ├── BundleUtil.java │ │ │ ├── FilterUtil.java │ │ │ └── SingleServiceTracker.java │ │ ├── service/ │ │ │ └── ServiceUtil.java │ │ ├── store/ │ │ │ └── listener/ │ │ │ ├── ConnectionListenerManager.java │ │ │ └── package-info.java │ │ ├── useradmin/ │ │ │ └── UserAdminHelper.java │ │ ├── validation/ │ │ │ ├── PasswordStrengthValidators.java │ │ │ ├── PredicateValidator.java │ │ │ ├── RegexValidator.java │ │ │ ├── Validator.java │ │ │ └── ValidatorOptions.java │ │ ├── wire/ │ │ │ └── store/ │ │ │ ├── AbstractJdbcQueryableWireRecordStoreImpl.java │ │ │ ├── AbstractJdbcWireRecordStoreImpl.java │ │ │ └── JdbcWireRecordStoreQueries.java │ │ └── zip/ │ │ └── UnZip.java │ ├── org.eclipse.kura.wire.camel/ │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ ├── metatype/ │ │ │ │ ├── org.eclipse.kura.wire.camel.CamelConsume.xml │ │ │ │ ├── org.eclipse.kura.wire.camel.CamelProcess.xml │ │ │ │ └── org.eclipse.kura.wire.camel.CamelProduce.xml │ │ │ ├── org.eclipse.kura.wire.camel.CamelConsume.xml │ │ │ ├── org.eclipse.kura.wire.camel.CamelProcess.xml │ │ │ └── org.eclipse.kura.wire.camel.CamelProduce.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── wire/ │ │ └── camel/ │ │ ├── AbstractCamelWireComponent.java │ │ ├── AbstractEndpointWireComponent.java │ │ ├── AbstractReceiverWireComponent.java │ │ ├── AbstractWireComponent.java │ │ ├── CamelConsume.java │ │ ├── CamelProcess.java │ │ └── CamelProduce.java │ ├── org.eclipse.kura.xml.marshaller.unmarshaller.provider/ │ │ ├── .gitignore │ │ ├── META-INF/ │ │ │ └── MANIFEST.MF │ │ ├── OSGI-INF/ │ │ │ └── XmlMarshallerUnmarshallerComponent.xml │ │ ├── about.html │ │ ├── build.properties │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── java/ │ │ └── org/ │ │ └── eclipse/ │ │ └── kura/ │ │ └── internal/ │ │ └── xml/ │ │ └── marshaller/ │ │ └── unmarshaller/ │ │ ├── XmlJavaBundlesMapper.java │ │ ├── XmlJavaComponentConfigurationsMapper.java │ │ ├── XmlJavaContainerImagesMapper.java │ │ ├── XmlJavaDataMapper.java │ │ ├── XmlJavaDockerContainersMapper.java │ │ ├── XmlJavaMetadataMapper.java │ │ ├── XmlJavaPackagesMapper.java │ │ ├── XmlJavaSnapshotIdResultMapper.java │ │ ├── XmlJavaSystemPackagesMapper.java │ │ ├── XmlJavaSystemResourcesMapper.java │ │ └── XmlMarshallUnmarshallImpl.java │ ├── pom.xml │ ├── setups/ │ │ ├── formatting/ │ │ │ ├── KuraCleanupProfile.xml │ │ │ └── KuraFormatter.xml │ │ ├── kura.setup │ │ ├── launchers/ │ │ │ ├── build-full.launch │ │ │ └── build-target-platform.launch │ │ └── toolchains/ │ │ ├── toolchains-rhel7.xml │ │ └── toolchains-travis.xml │ ├── target-definition/ │ │ ├── kura-equinox.target │ │ └── pom.xml │ ├── test/ │ │ ├── org.eclipse.kura.camel.test/ │ │ │ ├── .gitignore │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── camel/ │ │ │ │ ├── DependencyRunnerTest.java │ │ │ │ ├── component/ │ │ │ │ │ ├── AbstractRouterTest.java │ │ │ │ │ ├── PayloadTest.java │ │ │ │ │ ├── RouterTest.java │ │ │ │ │ └── xml/ │ │ │ │ │ ├── payload1.xml │ │ │ │ │ ├── test1.xml │ │ │ │ │ ├── test1a.xml │ │ │ │ │ └── test2.xml │ │ │ │ ├── runner/ │ │ │ │ │ └── ScriptRunnerTest.java │ │ │ │ └── type/ │ │ │ │ └── TypeConverterTest.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── camel/ │ │ │ ├── bean/ │ │ │ │ └── PayloadFactoryTest.java │ │ │ ├── camelcloud/ │ │ │ │ └── DefaultCamelCloudServiceTest.java │ │ │ ├── cloud/ │ │ │ │ ├── KuraCloudComponentResolverTest.java │ │ │ │ ├── KuraCloudComponentTest.java │ │ │ │ └── KuraCloudProducerTest.java │ │ │ ├── component/ │ │ │ │ └── ConfigurationTest.java │ │ │ └── internal/ │ │ │ ├── camelcloud/ │ │ │ │ └── CamelCloudClientTest.java │ │ │ └── utils/ │ │ │ └── KuraServiceFactoryTest.java │ │ ├── org.eclipse.kura.cloud.base.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── test/ │ │ │ │ ├── BaseCloudTests.java │ │ │ │ ├── CloudServiceTest.java │ │ │ │ ├── DataServiceTest.java │ │ │ │ └── MqttDataTransportTest.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── data/ │ │ │ ├── DataServiceImplTest.java │ │ │ ├── DataServiceOptionsTest.java │ │ │ └── ScheduleStrategyTest.java │ │ ├── org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/ │ │ │ ├── .gitignore │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── cloud-publisher.xml │ │ │ │ └── cloud-test.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── cloud/ │ │ │ │ ├── CloudPublisherImplTest.java │ │ │ │ └── CloudServiceTest.java │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ ├── cloud/ │ │ │ │ │ ├── BirthMessagesTest.java │ │ │ │ │ ├── CloudClientImplTest.java │ │ │ │ │ ├── CloudServiceImplTest.java │ │ │ │ │ ├── CloudServiceOptionsTest.java │ │ │ │ │ ├── LifeCyclePayloadBuilderTest.java │ │ │ │ │ └── publisher/ │ │ │ │ │ ├── CloudPublisherImplTest.java │ │ │ │ │ ├── CloudPublisherOptionsTest.java │ │ │ │ │ └── NotificationPublisherImplTest.java │ │ │ │ └── message/ │ │ │ │ ├── KuraBirthPayloadTest.java │ │ │ │ ├── KuraDisconnectPayloadTest.java │ │ │ │ └── protobuf/ │ │ │ │ ├── KuraPayloadProtoBuilderTest.java │ │ │ │ ├── KuraPayloadProtoMetricBuilderTest.java │ │ │ │ └── KuraPayloadProtoPositionBuilderTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── SparkplugIntegrationTest.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── java/ │ │ │ │ │ └── org/ │ │ │ │ │ └── eclipse/ │ │ │ │ │ └── kura/ │ │ │ │ │ └── cloudconnection/ │ │ │ │ │ └── sparkplug/ │ │ │ │ │ └── mqtt/ │ │ │ │ │ └── provider/ │ │ │ │ │ └── test/ │ │ │ │ │ ├── SparkplugDataTransportTest.java │ │ │ │ │ ├── SparkplugDeviceTest.java │ │ │ │ │ └── SparkplugIntegrationTest.java │ │ │ │ └── resources/ │ │ │ │ └── config/ │ │ │ │ └── moquette.conf │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── cloudconnection/ │ │ │ └── sparkplug/ │ │ │ └── mqtt/ │ │ │ ├── endpoint/ │ │ │ │ └── test/ │ │ │ │ ├── CloudDeliveryListenerTest.java │ │ │ │ ├── ConnectionStatusCallbackTest.java │ │ │ │ ├── DataServiceTest.java │ │ │ │ ├── StepsCollection.java │ │ │ │ ├── SubscriptionRecordTest.java │ │ │ │ └── SubscriptionsMapTest.java │ │ │ ├── factory/ │ │ │ │ └── test/ │ │ │ │ └── SparkplugCloudConnectionFactoryTest.java │ │ │ ├── message/ │ │ │ │ └── test/ │ │ │ │ ├── SparkplugBProtobufPayloadBuilderTest.java │ │ │ │ └── TypeMapperCase.java │ │ │ ├── subscriber/ │ │ │ │ └── test/ │ │ │ │ └── SparkplugSubscriberTest.java │ │ │ └── transport/ │ │ │ └── test/ │ │ │ ├── ConfigurationUpdateTest.java │ │ │ └── SparkplugDataTransportOptionsTest.java │ │ ├── org.eclipse.kura.configuration.change.manager.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── configuration/ │ │ │ └── change/ │ │ │ └── manager/ │ │ │ └── test/ │ │ │ ├── ComponentsServiceTrackerTest.java │ │ │ ├── ConfigurationChangeManagerOptionsTest.java │ │ │ ├── ConfigurationChangeManagerTest.java │ │ │ └── mocks/ │ │ │ ├── MockCloudPublisher.java │ │ │ └── MockServiceTracker.java │ │ ├── org.eclipse.kura.container.orchestration.provider.test/ │ │ │ ├── .gitignore │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── container/ │ │ │ └── orchestration/ │ │ │ └── provider/ │ │ │ ├── ContainerConfigurationTest.java │ │ │ ├── ContainerInstanceDescriptorTest.java │ │ │ ├── ContainerOrchestrationServiceImplTest.java │ │ │ ├── ContainerOrchestrationServiceOptionsTest.java │ │ │ ├── EnforcementSecurityTest.java │ │ │ └── ImageInstanceDescriptorTest.java │ │ ├── org.eclipse.kura.container.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── container/ │ │ │ └── provider/ │ │ │ ├── ContainerIdentityIntegrationTest.java │ │ │ ├── ContainerInstanceOptionsTest.java │ │ │ └── ContainerInstanceTest.java │ │ ├── org.eclipse.kura.core.certificates.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── certificates/ │ │ │ │ └── CertificatesManagerTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.cloud.factory.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── cloud/ │ │ │ └── factory/ │ │ │ └── DefaultCloudServiceFactoryTest.java │ │ ├── org.eclipse.kura.core.comm.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── comm/ │ │ │ │ └── CommConnectionImplTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.configuration.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── CfgSvcTestComponent.xml │ │ │ │ ├── CfgSvcTestSelfComponent.xml │ │ │ │ ├── ConfigurationServiceTest.xml │ │ │ │ └── metatype/ │ │ │ │ ├── org.eclipse.kura.core.configuration.CfgSvcTestComponent.xml │ │ │ │ └── org.eclipse.kura.core.configuration.TestFactoryComponent.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── configuration/ │ │ │ │ ├── CfgSvcTestComponent.java │ │ │ │ ├── CfgSvcTestSelfComponent.java │ │ │ │ └── ConfigurationServiceTest.java │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── configuration/ │ │ │ │ ├── ConfigurationServiceJunitTest.java │ │ │ │ └── util/ │ │ │ │ └── ComponentUtilTest.java │ │ │ └── resources/ │ │ │ ├── expected_snapshot_with_description.xml │ │ │ ├── expected_snapshot_without_description.xml │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.crypto.test/ │ │ │ ├── .gitignore │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── crypto/ │ │ │ ├── Base64Test.java │ │ │ ├── CryptoServiceImplCustomKeyTest.java │ │ │ ├── EncryptDecryptTest.java │ │ │ └── SystemdCredentialLoaderTest.java │ │ ├── org.eclipse.kura.core.identity.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── identity/ │ │ │ └── test/ │ │ │ ├── IdentityServiceImplTest.java │ │ │ ├── IdentityServiceTestBase.java │ │ │ ├── PasswordStrengthVerificationServiceImplTest.java │ │ │ └── TemporaryIdentityServiceTest.java │ │ ├── org.eclipse.kura.core.inventory.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── inventory/ │ │ │ └── InventoryHandlerV1Test.java │ │ ├── org.eclipse.kura.core.keystore.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── keystore/ │ │ │ │ ├── FilesystemKeystoreServiceImplTest.java │ │ │ │ ├── FilesystemKeystoreServiceOptionsTest.java │ │ │ │ ├── crl/ │ │ │ │ │ └── test/ │ │ │ │ │ └── FilesystemKeystoreServiceImplCrlTest.java │ │ │ │ └── util/ │ │ │ │ ├── CertificateUtilTest.java │ │ │ │ └── KeystoreUtilsTest.java │ │ │ └── resources/ │ │ │ ├── cert │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.ssl.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── ssl/ │ │ │ │ ├── ConnectionSslOptionsTest.java │ │ │ │ ├── SSLSocketFactoryWrapperTest.java │ │ │ │ └── SslManagerServiceImplTest.java │ │ │ └── resources/ │ │ │ ├── cert │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.status.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── status/ │ │ │ │ ├── CloudConnectionStatusServiceImplTest.java │ │ │ │ └── CloudConnectionStatusURLTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.system.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── system-test.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── system/ │ │ │ │ └── test/ │ │ │ │ └── SystemServiceTest.java │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── system/ │ │ │ │ └── SystemServiceTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.core.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── InventoryHandler-test.xml │ │ │ │ ├── all-core-tests.xml │ │ │ │ ├── cloudDeploymentHandler-test.xml │ │ │ │ ├── comm-test.xml │ │ │ │ ├── configuration-test.xml │ │ │ │ ├── example-test.xml │ │ │ │ ├── metatype/ │ │ │ │ │ └── org.eclipse.kura.core.test.IConfigurationServiceTest.xml │ │ │ │ ├── network-test.xml │ │ │ │ └── systemAdmin-test.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── kura/ │ │ │ │ └── packages/ │ │ │ │ └── com.eurotech.app.helloworld.dp │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── java/ │ │ │ │ │ └── org/ │ │ │ │ │ └── eclipse/ │ │ │ │ │ └── kura/ │ │ │ │ │ └── core/ │ │ │ │ │ └── test/ │ │ │ │ │ ├── AllCoreTests.java │ │ │ │ │ ├── CloudEndpointPublisher.java │ │ │ │ │ ├── CommURITest.java │ │ │ │ │ ├── ComponentConfigurationImplTest.java │ │ │ │ │ ├── ConfigurationServiceTest.java │ │ │ │ │ ├── ExampleTest.java │ │ │ │ │ ├── IConfigurationServiceTest.java │ │ │ │ │ ├── InventoryHandlerTest.java │ │ │ │ │ ├── NetUtilTest.java │ │ │ │ │ ├── NetworkServiceTest.java │ │ │ │ │ ├── RequestIdGenerator.java │ │ │ │ │ ├── SystemAdminServiceTest.java │ │ │ │ │ ├── hw/ │ │ │ │ │ │ ├── CommTest.java │ │ │ │ │ │ └── RxTxTest.java │ │ │ │ │ └── util/ │ │ │ │ │ └── CoreTestXmlUtil.java │ │ │ │ └── resources/ │ │ │ │ ├── artemis_config.xml │ │ │ │ ├── kura.properties │ │ │ │ ├── log4j.properties │ │ │ │ ├── moquette/ │ │ │ │ │ └── config/ │ │ │ │ │ ├── moquette.conf │ │ │ │ │ └── password_file.conf │ │ │ │ └── org.eclipse.kura.test.helloworld.dp │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ ├── internal/ │ │ │ │ └── linux/ │ │ │ │ └── executor/ │ │ │ │ ├── CommandLineMatcher.java │ │ │ │ ├── ExecutorUtilExecutionTest.java │ │ │ │ ├── ExecutorUtilRunningTest.java │ │ │ │ └── ExecutorUtilTerminationTest.java │ │ │ └── linux/ │ │ │ └── executor/ │ │ │ ├── CommandExecutionTest.java │ │ │ ├── CommandPidTest.java │ │ │ ├── CommandRunningTest.java │ │ │ └── CommandTerminationTest.java │ │ ├── org.eclipse.kura.core.util.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── core/ │ │ │ │ └── util/ │ │ │ │ ├── NetUtilTest.java │ │ │ │ ├── ProcessUtilTest.java │ │ │ │ ├── SafeProcessTest.java │ │ │ │ └── ValidationUtilTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.db.h2db.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── db/ │ │ │ └── h2db/ │ │ │ └── provider/ │ │ │ ├── DbDataStoreStorageTest.java │ │ │ └── H2DbServiceImplTest.java │ │ ├── org.eclipse.kura.db.sqlite.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── db/ │ │ │ │ └── sqlite/ │ │ │ │ └── provider/ │ │ │ │ └── test/ │ │ │ │ ├── SqliteDbServiceImplTest.java │ │ │ │ ├── SqliteDbServiceTestBase.java │ │ │ │ └── SqliteDebugShellTest.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── db/ │ │ │ └── sqlite/ │ │ │ └── provider/ │ │ │ ├── DatabaseLoaderTest.java │ │ │ ├── SqliteDbServiceOptionsTest.java │ │ │ └── SqliteProviderActivatorTest.java │ │ ├── org.eclipse.kura.driver.block.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── driver/ │ │ │ └── block/ │ │ │ └── test/ │ │ │ ├── AbstractBlockDriverTest.java │ │ │ ├── BinaryDataTest.java │ │ │ ├── BlockAggregatorTest.java │ │ │ ├── BlockTaskAggregatorTest.java │ │ │ └── BlockTaskTest.java │ │ ├── org.eclipse.kura.driver.helper.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── driver/ │ │ │ └── block/ │ │ │ └── test/ │ │ │ ├── DriveDescriptorServiceImplTest.java │ │ │ └── DriverServiceImplTest.java │ │ ├── org.eclipse.kura.emulator.position.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── position/ │ │ │ └── PositionServiceImplTest.java │ │ ├── org.eclipse.kura.emulator.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── emulator/ │ │ │ │ └── EmulatorTest.java │ │ │ └── resources/ │ │ │ └── log4j2.xml │ │ ├── org.eclipse.kura.emulator.watchdog.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── emulator/ │ │ │ └── watchdog/ │ │ │ └── WatchdogServiceImplTest.java │ │ ├── org.eclipse.kura.event.publisher.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── event/ │ │ │ │ └── publisher/ │ │ │ │ └── test/ │ │ │ │ └── EventPublisherTest.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── event/ │ │ │ └── publisher/ │ │ │ └── test/ │ │ │ ├── CloudDeliveryListenersTest.java │ │ │ ├── CloudEndpointServiceHelperTest.java │ │ │ ├── CloudEndpointServiceTrackerTest.java │ │ │ └── EventPublisherOptionsTest.java │ │ ├── org.eclipse.kura.http.server.manager.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── org.eclipse.kura.https.server.manager.test.HttpServiceTest.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── https/ │ │ │ └── server/ │ │ │ └── manager/ │ │ │ └── test/ │ │ │ └── HttpServiceTest.java │ │ ├── org.eclipse.kura.internal.driver.s7plc.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── driver/ │ │ │ └── s7plc/ │ │ │ ├── S7PlcChannelDescriptorTest.java │ │ │ ├── S7PlcDriverTest.java │ │ │ └── task/ │ │ │ ├── S7PlcTaskBuilderTest.java │ │ │ └── S7PlcToplevelBlockTaskTest.java │ │ ├── org.eclipse.kura.json.marshaller.unmarshaller.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── json/ │ │ │ └── marshaller/ │ │ │ └── unmarshaller/ │ │ │ ├── keystore/ │ │ │ │ └── test/ │ │ │ │ └── KeystoreEntryInfoMapperTest.java │ │ │ ├── message/ │ │ │ │ └── test/ │ │ │ │ ├── CloudPayloadJsonDecoderTest.java │ │ │ │ └── CloudPayloadJsonEncoderTest.java │ │ │ └── test/ │ │ │ └── JsonEncoderDecoderTest.java │ │ ├── org.eclipse.kura.linux.clock.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── linux/ │ │ │ │ └── clock/ │ │ │ │ ├── ChronyClockSyncProviderTest.java │ │ │ │ ├── ClockServiceImplTest.java │ │ │ │ └── JavaNtpClockSyncProviderTest.java │ │ │ └── resources/ │ │ │ ├── chrony.conf │ │ │ └── journal-entry.json │ │ ├── org.eclipse.kura.linux.usb.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── linux/ │ │ │ └── usb/ │ │ │ └── UsbServiceImplTest.java │ │ ├── org.eclipse.kura.linux.watchdog.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── linux/ │ │ │ └── watchdog/ │ │ │ ├── RebootCauseFileWriterTest.java │ │ │ └── WatchdogServiceImplTest.java │ │ ├── org.eclipse.kura.log.filesystem.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── log/ │ │ │ └── filesystem/ │ │ │ └── provider/ │ │ │ ├── FilesystemLogProviderTest.java │ │ │ └── KuraLogLineParserTest.java │ │ ├── org.eclipse.kura.message.store.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── message/ │ │ │ └── store/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ ├── MessageStoreProviderTest.java │ │ │ └── TestTarget.java │ │ ├── org.eclipse.kura.protocol.modbus.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── protocol/ │ │ │ └── modbus/ │ │ │ ├── ModbusProtocolDeviceTest.java │ │ │ └── test/ │ │ │ ├── ModbusHandler.java │ │ │ └── ModbusServer.java │ │ ├── org.eclipse.kura.raspberrypi.sensehat.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── raspberrypi/ │ │ │ │ └── sensehat/ │ │ │ │ ├── ledmatrix/ │ │ │ │ │ ├── FrameBufferTest.java │ │ │ │ │ └── Images.java │ │ │ │ └── sensors/ │ │ │ │ ├── HTS221Test.java │ │ │ │ ├── KuraI2CDevice.java │ │ │ │ ├── LPS25HTest.java │ │ │ │ ├── LSM9DS1Test.java │ │ │ │ └── dummydevices/ │ │ │ │ ├── DummyDevice.java │ │ │ │ ├── HTS221DummyDevice.java │ │ │ │ ├── LPS25HDummyDevice.java │ │ │ │ ├── LSM9DS1TAccDummyyDevice.java │ │ │ │ └── LSM9DS1TMagDummyyDevice.java │ │ │ └── resources/ │ │ │ └── test-sensehat_text.pbm │ │ ├── org.eclipse.kura.rest.cloudconnection.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── internal/ │ │ │ │ └── rest/ │ │ │ │ └── cloudconnection/ │ │ │ │ └── provider/ │ │ │ │ └── test/ │ │ │ │ └── CloudConnectionEndpointsTest.java │ │ │ └── resources/ │ │ │ ├── getStackComponentPidsResponse.json │ │ │ ├── isConnectedResponse.json │ │ │ └── updateConfigurationRequest.json │ │ ├── org.eclipse.kura.rest.configuration.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── rest/ │ │ │ └── configuration/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ ├── ConfigurationRestServiceTest.java │ │ │ └── ConfigurationUtil.java │ │ ├── org.eclipse.kura.rest.identity.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── java/ │ │ │ │ │ └── org/ │ │ │ │ │ └── eclipse/ │ │ │ │ │ └── kura/ │ │ │ │ │ └── internal/ │ │ │ │ │ └── rest/ │ │ │ │ │ └── identity/ │ │ │ │ │ └── provider/ │ │ │ │ │ └── test/ │ │ │ │ │ ├── IdentityV1EndpointsTest.java │ │ │ │ │ └── IdentityV2EndpointsTest.java │ │ │ │ └── resources/ │ │ │ │ ├── getNonExistingUserResponse.json │ │ │ │ ├── getPasswordRequirementsResponse.json │ │ │ │ ├── getUserConfigResponse.json │ │ │ │ └── getUserResponse.json │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── rest/ │ │ │ └── identity/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ ├── IdentityRestServiceV1DependenciesTest.java │ │ │ ├── IdentityRestServiceV2DependenciesTest.java │ │ │ └── IdentityServiceV1Test.java │ │ ├── org.eclipse.kura.rest.inventory.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── rest/ │ │ │ └── inventory/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ └── InventoryRestServiceTest.java │ │ ├── org.eclipse.kura.rest.keystore.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── rest/ │ │ │ │ └── keystore/ │ │ │ │ └── provider/ │ │ │ │ └── KeystoreRequestHandlerV2Test.java │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── rest/ │ │ │ │ └── keystore/ │ │ │ │ └── provider/ │ │ │ │ ├── KeystoreRestServiceTest.java │ │ │ │ └── request/ │ │ │ │ └── handler/ │ │ │ │ └── KeystoreServiceRequestHandlerTest.java │ │ │ └── resources/ │ │ │ ├── cert │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.rest.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── rest/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ ├── PasswordChangeSessionTest.java │ │ │ └── RestServiceTest.java │ │ ├── org.eclipse.kura.rest.security.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── internal/ │ │ │ │ └── rest/ │ │ │ │ └── security/ │ │ │ │ └── provider/ │ │ │ │ └── test/ │ │ │ │ ├── SecurityEndpointsV1Test.java │ │ │ │ └── SecurityEndpointsV2Test.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── rest/ │ │ │ └── security/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ └── SecurityServiceTest.java │ │ ├── org.eclipse.kura.rest.service.listing.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── TargetFilterTestService.xml │ │ │ │ ├── TestFactory1.xml │ │ │ │ ├── TestFactory2.xml │ │ │ │ └── metatype/ │ │ │ │ ├── org.eclipse.kura.internal.rest.service.listing.provider.test.TargetFilterTestService.xml │ │ │ │ ├── org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory1.xml │ │ │ │ └── org.eclipse.kura.internal.rest.service.listing.provider.test.TestFactory2.xml │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── rest/ │ │ │ └── service/ │ │ │ └── listing/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ ├── OtherTestInterface.java │ │ │ ├── ServiceListingEndpointsTest.java │ │ │ ├── TargetFilterTestService.java │ │ │ ├── TestInterface.java │ │ │ └── constants/ │ │ │ └── ServiceListeningTestConstants.java │ │ ├── org.eclipse.kura.rest.system.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ ├── java/ │ │ │ │ │ └── org/ │ │ │ │ │ └── eclipse/ │ │ │ │ │ └── kura/ │ │ │ │ │ └── rest/ │ │ │ │ │ └── system/ │ │ │ │ │ └── provider/ │ │ │ │ │ └── test/ │ │ │ │ │ ├── EndpointsTest.java │ │ │ │ │ └── SystemServiceMockDecorator.java │ │ │ │ └── resources/ │ │ │ │ ├── EXTENDED_PROPERTIES_FILTER_REQUEST │ │ │ │ ├── EXTENDED_PROPERTIES_RESPONSE │ │ │ │ ├── FRAMEWORK_PROPERTIES_FILTER_REQUEST │ │ │ │ ├── FRAMEWORK_PROPERTIES_RESPONSE │ │ │ │ ├── KURA_PROPERTIES_FILTER_REQUEST │ │ │ │ └── KURA_PROPERTIES_RESPONSE │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── rest/ │ │ │ └── system/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ └── DependenciesTest.java │ │ ├── org.eclipse.kura.rest.tamper.detection.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── rest/ │ │ │ └── tamper/ │ │ │ └── detection/ │ │ │ └── provider/ │ │ │ └── test/ │ │ │ └── TamperDetectionRemoteServiceTest.java │ │ ├── org.eclipse.kura.stress.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── stress/ │ │ │ │ └── test/ │ │ │ │ └── StressTest.java │ │ │ └── resources/ │ │ │ └── log4j.properties │ │ ├── org.eclipse.kura.test.helloworld/ │ │ │ ├── .gitignore │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── helloworld.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── test/ │ │ │ │ └── helloworld/ │ │ │ │ └── HelloWorld.java │ │ │ └── resources/ │ │ │ └── org.eclipse.kura.test.helloworld.dpp │ │ ├── org.eclipse.kura.useradmin.store.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── useradmin/ │ │ │ └── store/ │ │ │ └── test/ │ │ │ └── RoleRepositoryStoreTest.java │ │ ├── org.eclipse.kura.util.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ ├── osgi/ │ │ │ │ │ ├── BundleUtilTest.java │ │ │ │ │ └── SingleServiceTrackerTest.java │ │ │ │ └── util/ │ │ │ │ └── base/ │ │ │ │ └── ConvertStringTest.java │ │ │ └── test/ │ │ │ ├── java/ │ │ │ │ └── org/ │ │ │ │ └── eclipse/ │ │ │ │ └── kura/ │ │ │ │ └── util/ │ │ │ │ ├── FilterUtilTest.java │ │ │ │ └── zip/ │ │ │ │ └── UnZipTest.java │ │ │ └── resources/ │ │ │ └── uncompressedFile.txt │ │ ├── org.eclipse.kura.watchdog.criticaltest/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── component.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── watchdog/ │ │ │ └── criticaltest/ │ │ │ └── FailingCriticalComponent.java │ │ ├── org.eclipse.kura.xml.marshaller.unmarshaller.provider.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── internal/ │ │ │ └── xml/ │ │ │ └── marshaller/ │ │ │ └── unmarshaller/ │ │ │ └── test/ │ │ │ └── XmlEncoderDecoderTest.java │ │ └── pom.xml │ ├── test-util/ │ │ ├── org.eclipse.kura.core.testutil/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── core/ │ │ │ └── testutil/ │ │ │ ├── AssumingIsNotJenkins.java │ │ │ ├── AssumingIsNotMac.java │ │ │ ├── TestUtil.java │ │ │ ├── event/ │ │ │ │ └── EventAdminUtil.java │ │ │ ├── http/ │ │ │ │ └── TestServer.java │ │ │ ├── json/ │ │ │ │ └── JsonProjection.java │ │ │ ├── pki/ │ │ │ │ └── TestCA.java │ │ │ ├── requesthandler/ │ │ │ │ ├── AbstractRequestHandlerTest.java │ │ │ │ ├── MqttTransport.java │ │ │ │ ├── RestTransport.java │ │ │ │ ├── Transport.java │ │ │ │ └── TransportType.java │ │ │ └── service/ │ │ │ └── ServiceUtil.java │ │ ├── org.eclipse.kura.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ └── test.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── test/ │ │ │ ├── RemoteTargetTest.java │ │ │ ├── Test.java │ │ │ ├── TestExtender.java │ │ │ └── annotation/ │ │ │ └── TestTarget.java │ │ ├── org.eclipse.kura.util.test.driver/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── metatype/ │ │ │ │ │ └── org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver.xml │ │ │ │ └── org.eclipse.kura.util.test.driver.ChannelDescriptorTestDriver.xml │ │ │ ├── about.html │ │ │ ├── about_files/ │ │ │ │ └── epl-v20.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── util/ │ │ │ └── test/ │ │ │ └── driver/ │ │ │ └── ChannelDescriptorTestDriver.java │ │ ├── org.eclipse.kura.util.wire.test/ │ │ │ ├── META-INF/ │ │ │ │ └── MANIFEST.MF │ │ │ ├── OSGI-INF/ │ │ │ │ ├── TestEmitterReceiver.xml │ │ │ │ └── metatype/ │ │ │ │ └── org.eclipse.kura.util.wire.test.TestEmitterReceiver.xml │ │ │ ├── about.html │ │ │ ├── build.properties │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── kura/ │ │ │ └── util/ │ │ │ └── wire/ │ │ │ └── test/ │ │ │ ├── GraphBuilder.java │ │ │ ├── TestEmitterReceiver.java │ │ │ └── WireTestUtil.java │ │ └── pom.xml │ └── tools/ │ ├── kura-addon-archetype/ │ │ ├── .gitignore │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ └── resources/ │ │ ├── META-INF/ │ │ │ └── maven/ │ │ │ └── archetype-metadata.xml │ │ └── archetype-resources/ │ │ ├── .gitignore │ │ ├── __package__/ │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ └── main/ │ │ │ └── java/ │ │ │ ├── ExampleComponent.java │ │ │ ├── ExampleComponentOCD.java │ │ │ ├── ExampleComponentOptions.java │ │ │ ├── ExampleDependencyService.java │ │ │ ├── ExampleDependencyServiceComponent.java │ │ │ └── Property.java │ │ ├── bom/ │ │ │ └── pom.xml │ │ ├── distrib/ │ │ │ ├── deb/ │ │ │ │ └── control/ │ │ │ │ └── control │ │ │ └── pom.xml │ │ ├── pom.xml │ │ └── tests/ │ │ ├── __package__.test/ │ │ │ ├── integration-test.bndrun │ │ │ ├── pom.xml │ │ │ └── src/ │ │ │ ├── main/ │ │ │ │ └── java/ │ │ │ │ └── test/ │ │ │ │ └── ExampleComponentItTest.java │ │ │ └── test/ │ │ │ └── java/ │ │ │ └── test/ │ │ │ └── ExampleComponentTest.java │ │ ├── pom.xml │ │ └── test-env/ │ │ ├── data/ │ │ │ └── .gitkeep │ │ ├── framework/ │ │ │ └── kura.properties │ │ ├── log4j/ │ │ │ └── log4j.xml │ │ └── user/ │ │ └── snapshots/ │ │ └── snapshot_0.xml │ ├── pom.xml │ └── update-cert.sh ├── suppressions.xml └── target-platform/ ├── com.codeminders.hidapi-parent/ │ ├── com.codeminders.hidapi/ │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── LICENSE-bsd.txt │ │ ├── build.properties │ │ ├── build.xml │ │ ├── pom.xml │ │ └── src/ │ │ ├── AUTHORS.txt │ │ ├── LICENSE-bsd.txt │ │ ├── LICENSE-gpl3.txt │ │ ├── LICENSE-orig.txt │ │ ├── LICENSE.txt │ │ ├── hidapi/ │ │ │ └── hidapi.h │ │ ├── hidtest/ │ │ │ └── hidtest.cpp │ │ ├── jni-impl/ │ │ │ ├── HIDDevice.cpp │ │ │ ├── HIDDeviceInfo.cpp │ │ │ ├── HIDManager.cpp │ │ │ ├── hid-java.cpp │ │ │ └── hid-java.h │ │ ├── jni-stubs/ │ │ │ ├── com_codeminders_hidapi_HIDDevice.h │ │ │ ├── com_codeminders_hidapi_HIDDeviceInfo.h │ │ │ └── com_codeminders_hidapi_HIDManager.h │ │ ├── linux/ │ │ │ ├── Makefile │ │ │ ├── README.txt │ │ │ ├── hid-libusb.c │ │ │ └── hid.c │ │ ├── mac/ │ │ │ ├── Makefile │ │ │ └── hid.c │ │ └── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── codeminders/ │ │ │ ├── hidapi/ │ │ │ │ ├── ClassPathLibraryLoader.java │ │ │ │ ├── HIDAPITest.java │ │ │ │ ├── HIDDevice.java │ │ │ │ ├── HIDDeviceInfo.java │ │ │ │ ├── HIDDeviceNotFoundException.java │ │ │ │ └── HIDManager.java │ │ │ └── hidapplet/ │ │ │ └── HidApplet.java │ │ └── lib/ │ │ └── mac/ │ │ ├── x86/ │ │ │ └── libhidapi.jnilib │ │ └── x86_64/ │ │ └── libhidapi.jnilib │ ├── com.codeminders.hidapi.aarch64/ │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── LICENSE-bsd.txt │ │ ├── build.properties │ │ └── pom.xml │ ├── com.codeminders.hidapi.x86_64/ │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── LICENSE-bsd.txt │ │ ├── build.properties │ │ └── pom.xml │ └── pom.xml ├── log4j2-api-config/ │ ├── about.html │ ├── log4j-provider.properties │ └── pom.xml ├── org.eclipse.kura.camel.sun.misc/ │ ├── .gitignore │ ├── pom.xml │ └── src/ │ └── main/ │ └── resources/ │ └── about.html ├── org.eclipse.kura.sun.misc/ │ ├── .gitignore │ ├── pom.xml │ └── src/ │ └── main/ │ └── resources/ │ └── about.html ├── org.eclipse.soda.dk.comm-parent/ │ ├── org.eclipse.soda.dk.comm/ │ │ ├── OSGI-INF/ │ │ │ └── l10n/ │ │ │ ├── bundle.properties │ │ │ └── bundle_en.properties │ │ ├── TooManyListenersException.java │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v10.html │ │ ├── build.properties │ │ ├── build_native.sh │ │ ├── copyright.txt │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── c/ │ │ │ ├── .gitignore │ │ │ ├── CommPortIdentifier.c │ │ │ ├── Javaxcommnatives.vpj │ │ │ ├── Javaxcommnatives.vpw │ │ │ ├── Javaxcommnatives.vpwhist │ │ │ ├── Javaxcommnatives.vtg │ │ │ ├── NSCommDriver.c │ │ │ ├── NSCommLOG.c │ │ │ ├── NSCommLOG.h │ │ │ ├── NSDeviceInputStream.c │ │ │ ├── NSDeviceOutputStream.c │ │ │ ├── NSParallelPort.c │ │ │ ├── NSSerialPort.c │ │ │ ├── ParallelErrorEventThread.c │ │ │ ├── SerialDataEventThread.c │ │ │ ├── SerialStatusEventThread.c │ │ │ ├── SysVStyleSemaphore.c │ │ │ ├── SysVStyleSemaphore.h │ │ │ ├── build-mingw-win.bat │ │ │ ├── build-win.bat │ │ │ ├── build-win64.bat │ │ │ ├── cygCommDriver.c │ │ │ ├── cygCommPortIdentifier.c │ │ │ ├── cygDeviceInputStream.c │ │ │ ├── cygDeviceOutputStream.c │ │ │ ├── cygParallelErrorEventThread.c │ │ │ ├── cygParallelPort.c │ │ │ ├── cygSerialDataEventThread.c │ │ │ ├── cygSerialPort.c │ │ │ ├── cygSerialStatusEventThread.c │ │ │ ├── dkcomm.h │ │ │ ├── dkcomm22.h │ │ │ ├── javax_comm_CommPortIdentifier.h │ │ │ ├── makefile │ │ │ ├── makefile.linux │ │ │ ├── makefile.linux.arm_hf │ │ │ ├── makefile.linux.poky.arm_sf │ │ │ ├── makefile.linux.poky.i586 │ │ │ ├── makefile.linux.poky.x86_64 │ │ │ ├── makefile.mingw │ │ │ ├── makefile.mingw_win32 │ │ │ ├── makefile.mingw_win32_x64 │ │ │ ├── makefile.osx │ │ │ ├── makefile.qnx │ │ │ ├── makefile.win32 │ │ │ ├── makefile.win32_down │ │ │ ├── makefile.win32_x64 │ │ │ ├── makefile.wince │ │ │ ├── org_eclipse_soda_dk_comm_NSCommDriver.h │ │ │ ├── org_eclipse_soda_dk_comm_NSDeviceInputStream.h │ │ │ ├── org_eclipse_soda_dk_comm_NSDeviceOutputStream.h │ │ │ ├── org_eclipse_soda_dk_comm_NSParallelPort.h │ │ │ ├── org_eclipse_soda_dk_comm_NSSerialPort.h │ │ │ ├── org_eclipse_soda_dk_comm_ParallelErrorEventThread.h │ │ │ ├── org_eclipse_soda_dk_comm_SerialDataEventThread.h │ │ │ ├── org_eclipse_soda_dk_comm_SerialStatusEventThread.h │ │ │ ├── w32CommDriver.c │ │ │ ├── w32CommPortIdentifier.c │ │ │ ├── w32DeviceInputStream.c │ │ │ ├── w32DeviceOutputStream.c │ │ │ ├── w32ParallePort.h │ │ │ ├── w32ParallelErrorEventThread.c │ │ │ ├── w32ParallelPort.c │ │ │ ├── w32SerialDataEventThread.c │ │ │ ├── w32SerialPort.c │ │ │ ├── w32SerialPort.h │ │ │ └── w32SerialStatusEventThread.c │ │ ├── java/ │ │ │ ├── javax/ │ │ │ │ └── comm/ │ │ │ │ ├── CommDriver.java │ │ │ │ ├── CommPort.java │ │ │ │ ├── CommPortIdentifier.java │ │ │ │ ├── CommPortOwnershipListener.java │ │ │ │ ├── NoSuchPortException.java │ │ │ │ ├── ParallelPort.java │ │ │ │ ├── ParallelPortEvent.java │ │ │ │ ├── ParallelPortEventListener.java │ │ │ │ ├── PortInUseException.java │ │ │ │ ├── SerialPort.java │ │ │ │ ├── SerialPortEvent.java │ │ │ │ ├── SerialPortEventListener.java │ │ │ │ ├── SerialPortException.java │ │ │ │ ├── UnsupportedCommOperationException.java │ │ │ │ └── package.html │ │ │ └── org/ │ │ │ └── eclipse/ │ │ │ └── soda/ │ │ │ └── dk/ │ │ │ └── comm/ │ │ │ ├── DeviceList.java │ │ │ ├── DeviceListEntry.java │ │ │ ├── NSCommDriver.java │ │ │ ├── NSDeviceInputStream.java │ │ │ ├── NSDeviceOutputStream.java │ │ │ ├── NSParallelPort.java │ │ │ ├── NSSerialPort.java │ │ │ ├── ParallelErrorEventThread.java │ │ │ ├── SerialDataEventThread.java │ │ │ ├── SerialStatusEventThread.java │ │ │ ├── bundle/ │ │ │ │ ├── Activator.java │ │ │ │ └── package.html │ │ │ ├── internal/ │ │ │ │ ├── Library.java │ │ │ │ └── package.html │ │ │ └── package.html │ │ └── lib/ │ │ ├── mac/ │ │ │ └── x86/ │ │ │ └── libdkcomm.jnilib │ │ └── win32/ │ │ └── x86/ │ │ ├── dkcomm.exp │ │ ├── dkcomm.lib │ │ └── dkcomm.pdb │ ├── org.eclipse.soda.dk.comm.aarch64/ │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v10.html │ │ ├── build.properties │ │ ├── copyright.txt │ │ └── pom.xml │ ├── org.eclipse.soda.dk.comm.x86_64/ │ │ ├── about.html │ │ ├── about_files/ │ │ │ └── epl-v10.html │ │ ├── build.properties │ │ ├── copyright.txt │ │ └── pom.xml │ └── pom.xml ├── org.moka7/ │ ├── about.html │ ├── about_files/ │ │ ├── Eclipse Public License - Version 1.0.html │ │ ├── Moka-License.txt │ │ ├── gpl.txt │ │ └── lgpl-3.0.txt │ ├── build.properties │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── Moka7/ │ ├── IntByRef.java │ ├── S7.java │ ├── S7BlockInfo.java │ ├── S7Client.java │ ├── S7CpInfo.java │ ├── S7CpuInfo.java │ ├── S7OrderCode.java │ ├── S7Protection.java │ └── S7Szl.java ├── org.usb4java/ │ ├── .gitignore │ ├── about.html │ ├── about_files/ │ │ └── cpl-v10.html │ ├── build.properties │ └── pom.xml ├── pom.xml ├── target-platform-pde-deps/ │ └── pom.xml └── usb4java-javax/ ├── .gitignore ├── about.html ├── about_files/ │ └── cpl-v10.html ├── build.properties ├── pom.xml └── src/ └── main/ └── resources/ └── javax.usb.properties ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Set the default behavior, in case people don't have core.autocrlf set. * text=auto # force LF-only line endings *.java text eol=lf *.xml text eol=lf *.properties text eol=lf *.sh text eol=lf *.c text eol=lf *.h text eol=lf # Declare files that will always have CRLF line endings on checkout. *.sln text eol=crlf # Denote all files that are truly binary and should not be modified. *.png binary *.jpg binary *.catalog binary ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Target Environment (please complete the following information):** - Board [e.g. Raspberry Pi 3] - OS version: [e.g. provide the result of `uname -a`] - Additional info: **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/copyright-config.yml ================================================ # Enable or disable the copyright date check bypass_year_check: false # In the template the user can specify two variables: {years} and {holder} # - {years} will match the copyright years (regex: `\d{4}(,\s\d{4})?`) # - {holder} will match the copyright holder (regex: `[\w\s\.]+`) template_java: | ****************************************************************************** * Copyright (c) {years} {holder} and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * {holder} template_xml: |2 Copyright (c) {years} {holder} and/or its affiliates and others This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: {holder} # Ignore specific files and paths. The syntax and semantics are the same as in the .gitignore file. ignore: - target-platform/ - kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/ - suppressions.xml - /kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/*.gpx - /kura/tools/kura-addon-archetype/src/main/resources/archetype-resources/* ================================================ FILE: .github/release_notes_template/helper.hbs ================================================ Handlebars.registerHelper('firstLetters', function(input, options) { const number = parseInt(options.hash['number'] || "0") return input.substring(0,number); }); Handlebars.registerHelper('date', function() { const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; const date = new Date(); const month = monthNames[date.getMonth()]; const year = date.getYear() + 1900; return month + " " + year; }); ================================================ FILE: .github/release_notes_template/template.hbs ================================================ Eclipse Kura - {{extended.version}} - {{{date}}} ------------------------------------------------------------------------------------------------- Description: [TODO] {{#issues}} {{! Features section }} {{#ifContainsType commits type='feat'}} Features: {{#commits}} {{#ifCommitType . type='feat'}} * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}}) {{/ifCommitType}} {{/commits}} {{/ifContainsType}} {{! Target environments section }} Target Environments: [TODO] {{! Breaking changes section }} {{#ifContainsBreaking commits}} Breaking changes: {{#commits}} {{#ifCommitBreaking .}} * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}}) {{/ifCommitBreaking}} {{/commits}} {{/ifContainsBreaking}} {{! Bug Fixes section }} {{#ifContainsType commits type='fix'}} Bug Fixes: {{#commits}} {{#ifCommitType . type='fix'}} * {{firstLetters hash number='10'}} - {{#eachCommitScope .}}[{{.}}] {{/eachCommitScope}}{{{commitDescription .}}} ({{authorName}}) {{/ifCommitType}} {{/commits}} {{/ifContainsType}} {{! Deprecated APIs/components section }} {{#ifContainsType commits type='deprecate'}} Deprecated APIs/components: {{#commits}} {{#ifCommitType . type='deprecate'}} * {{firstLetters hash number='10'}} - {{{commitDescription .}}} ({{authorName}}) {{/ifCommitType}} {{/commits}} {{/ifContainsType}} {{! Target Platform updates section }} {{#ifContainsType commits type='build'}} Target Platform Updates: {{#commits}} {{#ifCommitType . type='build'}} * {{firstLetters hash number='10'}} - {{{commitDescription .}}} ({{authorName}}) {{/ifCommitType}} {{/commits}} {{/ifContainsType}} {{! Known issues section }} Known Issues: [TODO] {{! Changelog section }} Changelog: {{#commits}} * {{firstLetters hash number='10'}} - {{{messageTitle}}} ({{authorName}}) {{/commits}} {{/issues}} ================================================ FILE: .github/version_uptick_configs/uptick_major_on_develop_branch.yml ================================================ --- exclusions: - "**/.git/**/*" - "**/.github/**/*" - "**/target/**/*" - "**/RELEASE_INFO/**/*" - "**/.settings/**/*" - "**/.classpath" - "**/.project" - "./kura/tools/archetype/example/src/main/resources/**/*" tasks: - selector: and: - snapshot - not: artifact_id: "moquette-broker" actions: - print - transform_version: - add_major: 1 - set_minor: 0 - set_patch: 0 ================================================ FILE: .github/version_uptick_configs/uptick_minor_on_develop_branch.yml ================================================ --- exclusions: - "**/.git/**/*" - "**/.github/**/*" - "**/target/**/*" - "**/RELEASE_INFO/**/*" - "**/.settings/**/*" - "**/.classpath" - "**/.project" - "./kura/tools/archetype/example/src/main/resources/**/*" tasks: - selector: and: - snapshot - not: artifact_id: "moquette-broker" actions: - print - transform_version: - add_minor: 1 - set_patch: 0 ================================================ FILE: .github/version_uptick_configs/uptick_patch_on_maintenance_branch.yml ================================================ --- exclusions: - "**/.git/**/*" - "**/.github/**/*" - "**/target/**/*" - "**/RELEASE_INFO/**/*" - "**/.settings/**/*" - "**/.classpath" - "**/.project" - "./kura/tools/archetype/example/src/main/resources/**/*" tasks: - selector: and: - release - not: artifact_id: "moquette-broker" actions: - print - transform_version: - add_patch: 1 - snapshot: set ================================================ FILE: .github/version_uptick_configs/uptick_snapshot_to_patch_release.yml ================================================ --- exclusions: - "**/.git/**/*" - "**/.github/**/*" - "**/target/**/*" - "**/RELEASE_INFO/**/*" - "**/.settings/**/*" - "**/.classpath" - "**/.project" - "./kura/tools/archetype/example/src/main/resources/**/*" tasks: - selector: or: - and: - group_id: "org.eclipse.kura" - artifact_id: "distrib" - and: - group_id: "org.eclipse.kura" - artifact_id: "tools" - and: - group_id: "org.eclipse.kura" - artifact_id: "target-platform" - and: - group_id: "org.eclipse.kura" - artifact_id: "examples" - and: - group_id: "org.eclipse.kura.tools" - artifact_id: "archetype" - and: - group_id: "org.eclipse.kura" - artifact_id: "kura" actions: - print - transform_version: - snapshot: remove ================================================ FILE: .github/version_uptick_configs/uptick_snapshot_to_release.yml ================================================ --- exclusions: - "**/.git/**/*" - "**/.github/**/*" - "**/target/**/*" - "**/RELEASE_INFO/**/*" - "**/.settings/**/*" - "**/.classpath" - "**/.project" - "./kura/tools/archetype/example/src/main/resources/**/*" tasks: - selector: and: - snapshot - not: artifact_id: "moquette-broker" actions: - print - transform_version: - snapshot: remove ================================================ FILE: .github/workflows/backport.yml ================================================ name: Backport on: pull_request_target: types: - closed - labeled permissions: contents: write pull-requests: write jobs: call-workflow-in-public-repo: uses: eclipse-kura/.github/.github/workflows/_shared-backport.yml@main ================================================ FILE: .github/workflows/copyright-check.yml ================================================ name: Copyright check on: pull_request: types: [opened, reopened, synchronize] branches: - 'develop' - 'release-*' jobs: call-workflow-in-public-repo: uses: eclipse-kura/.github/.github/workflows/_shared-copyright-check.yml@main with: config-path: '.github/copyright-config.yml' ================================================ FILE: .github/workflows/force-merge.yml ================================================ name: "Force merge automation" description: Merge a pull request when N committers post a comment with the command /force-merge on: issue_comment: types: [created, edited, deleted] permissions: contents: write pull-requests: write issues: write jobs: call-workflow-in-public-repo: uses: eclipse-kura/.github/.github/workflows/_shared-force-merge.yml@main secrets: inherit ================================================ FILE: .github/workflows/kura-core-sbom.yml ================================================ name: Kura core SBOM upload on: schedule: # At 00:00 on Saturday - cron: "0 0 * * 6" workflow_dispatch: inputs: target_branch: type: string default: 'develop' required: true workflow_run: workflows: ["Release Notes automation"] types: - completed # Product specific settings env: JAVA_VERSION: '21' # java version used by the product JAVA_DISTRO: 'temurin' # java distro used by the product PRODUCT_PATH: "kura" # path within project repository for SBOM source PLUGIN_VERSION: '2.9.1' # cyclonedx-maven-plugin version to use WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} INPUT_TARGET_BRANCH: ${{ github.event.inputs.target_branch }} EVENT_NAME: ${{ github.event_name }} GITHUB_REF_NAME: ${{ github.ref_name }} permissions: contents: read jobs: generate-sbom: name: Generate Kura core SBOM runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} outputs: project-version: ${{ steps.get-version.outputs.PROJECT_VERSION }} # required for DependencyTrack upload steps: - name: Set checkout ref id: set-checkout-ref shell: bash run: | if [[ "$EVENT_NAME" == "workflow_run" ]]; then echo "CHECKOUT_REF=$WORKFLOW_HEAD_BRANCH" >> $GITHUB_ENV elif [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then echo "CHECKOUT_REF=$INPUT_TARGET_BRANCH" >> $GITHUB_ENV else echo "CHECKOUT_REF=$GITHUB_REF_NAME" >> $GITHUB_ENV fi - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 ref: ${{ env.CHECKOUT_REF }} - name: Debug branch information run: | echo "=== Debug Branch Information ===" echo "Event name: $EVENT_NAME" echo "Current branch (git): $(git branch --show-current)" echo "===============================" - name: Setup Java SDK uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: java-version: ${{ env.JAVA_VERSION }} distribution: ${{ env.JAVA_DISTRO }} - name: Generate sbom run: | mvn org.cyclonedx:cyclonedx-maven-plugin:${{ env.PLUGIN_VERSION }}:makeAggregateBom -DprojectType=framework -DexcludeArtifactId=target-definition,emulator,distrib,test,tools,kura-addon-archetype,kura-pde-deps -f ${{ env.PRODUCT_PATH }}/pom.xml - name: Extract product version id: get-version shell: bash run: | VERSION="$(jq -r '.metadata.component.version' < ./${{ env.PRODUCT_PATH }}/target/bom.json)" # Substitute "-SNAPSHOT" suffix with "@dev" if present VERSION="${VERSION/-SNAPSHOT/@dev}" echo "PROJECT_VERSION=$VERSION" >> $GITHUB_OUTPUT echo "Product version: $VERSION" - name: Upload sbom uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: kura-core-sbom path: ${{ env.PRODUCT_PATH }}/target/bom.json store-sbom-data: needs: ['generate-sbom'] uses: eclipse-csi/workflows/.github/workflows/store-sbom-data.yml@88508d92f2638d942a88744431f017225ed8c14c # main@08/04/2026 with: projectName: 'kura-core' projectVersion: ${{ needs.generate-sbom.outputs.project-version }} bomArtifact: 'kura-core-sbom' bomFilename: 'bom.json' parentProject: 'f295fa60-24df-44d9-83ff-00b3ff8d6131' ================================================ FILE: .github/workflows/release-notes.yml ================================================ name: "Release Notes automation" on: workflow_dispatch: inputs: starting_commit: type: string description: Commit from which to start generating the Release Notes (non-inclusive) required: true overwrite: type: boolean description: Overwrite the content of TODO fields in generated release notes (typically needed for RC1 notes) required: true default: false permissions: contents: write pull-requests: write jobs: main: name: Generate Release Notes runs-on: ubuntu-latest steps: - name: Checkout ${{ github.ref }} branch in ${{ github.repository }} repository. uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: fetch-depth: '0' - name: Setup Java uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' - name: Get version id: get-version run: "echo \"resolved-version=\ $(mvn --file ./kura/pom.xml -Dexec.executable=echo -Dexec.args='${project.version}' --quiet exec:exec --non-recursive )\" >> \"${GITHUB_OUTPUT}\"" shell: bash - name: Check file existence id: check_files continue-on-error: true uses: thebinaryfelix/check-file-existence-action@436223737a098725b8d10ab1950a03efba5e6fc6 # 1.0.0 with: files: './kura/distrib/RELEASE_NOTES.txt' - name: Files exist id: get-old-text if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false' run: | awk '/Description:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > description.txt awk '/Target Environments:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > target-env.txt awk '/Known Issues:/ {found=1; next} /^$/ {found=0} found {print}' ./kura/distrib/RELEASE_NOTES.txt > known-issues.txt shell: bash - name: Download git-changelog-command-line tool id: download-changelog-cli uses: clausnz/github-action-download-maven-artifact@bad2e2130cb9d8c86412124298e5ba22ab9cfb66 # 0.0.4 with: url: 'https://repo1.maven.org' repository: 'maven2' groupId: 'se.bjurr.gitchangelog' artifactId: 'git-changelog-command-line' version: '2.5.7' extension: 'jar' - name: Generate Release Notes run: | java -jar ${{ steps.download-changelog-cli.outputs.file }} \ -fc "${{ github.event.inputs.starting_commit }}" \ -ex "{\"version\":\"${{ steps.get-version.outputs.resolved-version }}\"}" \ -t .github/release_notes_template/template.hbs \ -hhf .github/release_notes_template/helper.hbs \ -of ./kura/distrib/RELEASE_NOTES.txt - name: Files exist write description id: get-description if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false' # Only runs if all of the files exist run: | awk 'NR==FNR { desc = (desc == "" ? $0 : desc "\n" $0); next } /\[TODO\]/ && !done { sub(/\[TODO\]/, desc); done=1 } 1' description.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt awk 'NR==FNR { desc = (desc == "" ? $0 : desc "\n" $0); next } /\[TODO\]/ && !done { sub(/\[TODO\]/, desc); done=1 } 1' target-env.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt awk 'NR==FNR { desc = (desc == "" ? $0 : desc "\n" $0); next } /\[TODO\]/ && !done { sub(/\[TODO\]/, desc); done=1 } 1' known-issues.txt done=0 ./kura/distrib/RELEASE_NOTES.txt > tmpfile && mv tmpfile ./kura/distrib/RELEASE_NOTES.txt shell: bash - name: Files exist clean up id: clean-up-files if: steps.check_files.outputs.exists == 'true' && github.event.inputs.overwrite == 'false' # Only runs if all of the files exist run: | rm description.txt rm target-env.txt rm known-issues.txt - name: Create Pull Request uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4 with: title: "chore: add Kura ${{ steps.get-version.outputs.resolved-version }} release notes" commit-message: "chore: add Kura ${{ steps.get-version.outputs.resolved-version }} release notes" body: "Automated changes by _Release Notes automation_ action: add Kura ${{ steps.get-version.outputs.resolved-version }} version release notes since commit `${{ github.event.inputs.starting_commit }}`" branch-suffix: short-commit-hash token: ${{ secrets.BOT_GITHUB_TOKEN }} ================================================ FILE: .github/workflows/semantic-pr.yml ================================================ name: "Lint PR" on: pull_request_target: types: - opened - edited - synchronize permissions: pull-requests: read jobs: call-workflow-in-public-repo: uses: eclipse-kura/.github/.github/workflows/_shared-pr-lint.yml@main ================================================ FILE: .github/workflows/stale-issues.yml ================================================ name: "Close inactive issues and PRs" on: schedule: - cron: "30 1 * * *" permissions: issues: write pull-requests: write jobs: close-issues: runs-on: ubuntu-latest permissions: issues: write pull-requests: write steps: - uses: actions/stale@f7176fd3007623b69d27091f9b9d4ab7995f0a06 # v5.2.1 with: days-before-issue-stale: 60 days-before-issue-close: 14 stale-issue-label: "stale" stale-issue-message: "This issue is stale because it has been open for 60 days with no activity." close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." exempt-issue-labels: exempt-stale days-before-pr-stale: 60 days-before-pr-close: 14 stale-pr-message: "This pull request is stale because it has been open for 60 days with no activity." close-pr-message: "This pull request was closed because it has been inactive for 14 days since being marked as stale." exempt-pr-labels: exempt-stale operations-per-run: 300 repo-token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/target-platform-sbom.yml ================================================ name: Target Platform SBOM upload on: schedule: # At 00:00 on Saturday - cron: "0 0 * * 6" workflow_dispatch: inputs: target_branch: type: string default: 'develop' required: true workflow_run: workflows: ["Release Notes automation"] types: - completed # Product specific settings env: JAVA_VERSION: '21' # java version used by the product JAVA_DISTRO: 'temurin' # java distro used by the product PRODUCT_PATH: 'target-platform' # path within project repository for SBOM source PLUGIN_VERSION: '2.9.1' # cyclonedx-maven-plugin version to use WORKFLOW_HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} INPUT_TARGET_BRANCH: ${{ github.event.inputs.target_branch }} EVENT_NAME: ${{ github.event_name }} GITHUB_REF_NAME: ${{ github.ref_name }} permissions: contents: read jobs: generate-sbom: name: Generate Kura target platform SBOM runs-on: ubuntu-latest if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} outputs: project-version: ${{ steps.get-version.outputs.PROJECT_VERSION }} # required for DependencyTrack upload steps: - name: Set checkout ref id: set-checkout-ref shell: bash run: | if [[ "$EVENT_NAME" == "workflow_run" ]]; then echo "CHECKOUT_REF=$WORKFLOW_HEAD_BRANCH" >> $GITHUB_ENV elif [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then echo "CHECKOUT_REF=$INPUT_TARGET_BRANCH" >> $GITHUB_ENV else echo "CHECKOUT_REF=$GITHUB_REF_NAME" >> $GITHUB_ENV fi - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 ref: ${{ env.CHECKOUT_REF }} - name: Debug branch information run: | echo "=== Debug Branch Information ===" echo "Event name: $EVENT_NAME" echo "Current branch (git): $(git branch --show-current)" echo "===============================" - name: Setup Java SDK uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: java-version: ${{ env.JAVA_VERSION }} distribution: ${{ env.JAVA_DISTRO }} - name: Generate sbom run: | mvn org.cyclonedx:cyclonedx-maven-plugin:${{ env.PLUGIN_VERSION }}:makeAggregateBom -DprojectType=framework -f ${{ env.PRODUCT_PATH }}/pom.xml - name: Extract product version id: get-version shell: bash run: | VERSION="$(jq -r '.metadata.component.version' < ./${{ env.PRODUCT_PATH }}/target/bom.json)" # Substitute "-SNAPSHOT" suffix with "@dev" if present VERSION="${VERSION/-SNAPSHOT/@dev}" echo "PROJECT_VERSION=$VERSION" >> $GITHUB_OUTPUT echo "Product version: $VERSION" - name: Upload sbom uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: name: target-platform-sbom path: ${{ env.PRODUCT_PATH }}/target/bom.json store-sbom-data: needs: ['generate-sbom'] uses: eclipse-csi/workflows/.github/workflows/store-sbom-data.yml@88508d92f2638d942a88744431f017225ed8c14c # main@08/04/2026 with: projectName: 'kura-target-platform' projectVersion: ${{ needs.generate-sbom.outputs.project-version }} bomArtifact: 'target-platform-sbom' bomFilename: 'bom.json' parentProject: '100d803b-679b-40c2-8e73-101e0bf363ba' ================================================ FILE: .github/workflows/version-uptick.yml ================================================ name: Version uptick automation on: workflow_dispatch: inputs: target_branch: type: string default: 'develop' required: true uptick_config: type: choice description: Configuration to use for the uptick options: - uptick_major_on_develop_branch.yml - uptick_minor_on_develop_branch.yml - uptick_patch_on_maintenance_branch.yml - uptick_snapshot_to_patch_release.yml - uptick_snapshot_to_release.yml required: true permissions: contents: write pull-requests: write jobs: uptick: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: ref: ${{ github.event.inputs.target_branch }} - name: Download version upticker tool uses: carlosperate/download-file-action@8b89cb8b4807765e7d63fe765cc600eb1919af11 # v1.1.2 with: file-url: https://kura-repo.s3.us-west-2.amazonaws.com/esf_upticker_tool/version-uptick-0.2.0-linux-x86_64 - name: Make the uptick tool executable run: | chmod +x ./version-uptick-0.2.0-linux-x86_64 shell: bash - name: Run the uptick tool run: | ./version-uptick-0.2.0-linux-x86_64 \ --commit --trace process-versions \ --config-path .github/version_uptick_configs/${{ github.event.inputs.uptick_config }} \ --root-dir . shell: bash - name: Cleanup uptick tool run: | rm ./version-uptick-0.2.0-linux-x86_64 shell: bash - name: Get version id: get-version uses: JActions/maven-version@aafa242403588c1c69d619b3cec9c2ff6abd57ac # v1.0.1 with: pom: ./kura/pom.xml - name: Create Pull Request uses: peter-evans/create-pull-request@38e0b6e68b4c852a5500a94740f0e535e0d7ba54 # v4.2.4 with: title: "chore: automated uptick to ${{ steps.get-version.outputs.version }}" commit-message: "chore: automated uptick to ${{ steps.get-version.outputs.version }}" body: "Automated changes by _Version uptick automation_ action: automated uptick to ${{ steps.get-version.outputs.version }} version" branch-suffix: timestamp token: ${{ secrets.BOT_GITHUB_TOKEN }} ================================================ FILE: .gitignore ================================================ # OS generated files # ###################### .DS_Store* *~ classes target .classpath .project .wtpmodules .settings .sonar .sonarlint .metadata .recommenders kura/data kura/snapshots kura/target-definition/*/plugins/* kura/target-definition/*/source/* kura/target-definition/repository/artifacts.xml kura/target-definition/repository/content.xml kura/target-definition/repository/plugins/* kura/target-definition/*/repository/artifacts.xml kura/target-definition/*/repository/content.xml kura/target-definition/*/repository/plugins/* kura/tools/archetype/example/src/main/resources/archetype-resources/target-definition target-platform/*/META-INF/MANIFEST.MF target-platform/*/*/META-INF/MANIFEST.MF kura/distrib/kura-target-definition/kura-target-definition.target gwt-unitCache .launch www-test .gwt *.cache.* manifests bin/ +# IntelliJ Idea .idea/ *.iml maven.deps DEPENDENCIES .java-version # VS Code javaConfig.json .vscode ================================================ FILE: .jenkins/nexusUtils.groovy ================================================ def uploadPackages(String repoDistribution, String repoModule, Boolean setupPromotion = false) { stage ("Upload packages parameters check") { echo "Distribution: ${repoDistribution}" echo "Module: ${repoModule}" // Check "distribution" parameter is set and valid assert repoDistribution instanceof String assert repoDistribution ==~ /kura-\d+/ // Check "module" parameter is set and valid def valid_modules = [ "base" ] assert repoModule instanceof String assert valid_modules.contains(repoModule) } stage("Upload .deb packages to Nexus") { def debFiles = findFiles(glob: 'kura/**/*.deb') if (debFiles.size() == 0) { error("No .deb files found to upload") } debFiles.each { withCredentials([usernameColonPassword(credentialsId: 'repo.eclipse.org-bot-account', variable: 'USERPASS')]) { def status = sh( script: """ curl -u \"\$USERPASS\" \ -w '%{http_code}' \ -H \"Content-Type: multipart/form-data\" \ --data-binary \"@./${it}\" \ \"https://repo.eclipse.org/repository/kura-apt-dev/\" \ -o /dev/null """, returnStdout: true ).trim() if (status != "201") { error("Returned status code = $status") } } } if (setupPromotion) { // TODO } } } return this ================================================ FILE: AGENTS.md ================================================ # Eclipse Kura Agent Guide ## Build Commands - **Full Build**: `mvn -f target-platform/pom.xml clean install && mvn -f kura/pom.xml clean install && mvn -f kura/distrib/pom.xml clean install -DbuildAll` - **Skip Tests**: Add `-Dmaven.test.skip=true` to any build command - **Run Single Test**: `mvn -f kura/test//pom.xml test` (e.g., `mvn -f kura/test/org.eclipse.kura.log.filesystem.provider.test/pom.xml test`) - **Checkstyle**: Runs automatically during `process-sources` phase with config in `checkstyle_checks.xml` ## Code Style - **Java Version**: Java 21 (source/target) - **Formatting**: Use profiles in `kura/setup/formatting/` (KuraFormatter.xml, KuraCleanupProfile.xml) - **Line Length**: Max 150 characters - **Imports**: No star imports, remove unused imports - **Line Endings**: Unix (LF) only, no Windows CRLF - **Comments**: DO NOT ADD COMMENTS unless explicitly requested - **Copyright**: Always update copyright year to 2026 if editing files; add `// Content with portions generated by generative AI platform` after copyright header - **Naming**: camelCase for variables/methods; UPPER_SNAKE_CASE for constants; loggers can be named `log`, `logger`, or `auditLogger` ## Testing - **Gherkin-Style Mandatory**: Every new unit or integration test must follow the Gherkin structure (Given/When/Then). Organize tests so that a single feature is covered per test class. - **Feature Classes**: Choose a concise feature name for the test class (e.g., `StoreWireEnvelopeTest`). Group features for the same component under the same package. If the feature becomes complex, split it into multiple classes. - **Scenarios as @Test Methods**: Place public scenario methods annotated with `@Test` at the top of the class. Scenario names describe the behavior (e.g., `successfulStoreOnExistingTable`). Scenario methods have no parameters and return `void`. Cover both happy and unhappy paths. - **Steps as Private Helpers**: Define private step methods after the scenarios. Step method names start with `given`, `when`, or `then`. Steps do not return values, can take arguments, and must contain the relevant assertions. Group steps in Given/When/Then order inside each scenario, separating groups with a blank line. - **Internal State**: Maintain intermediate state with fields when needed. Extract common setup logic into abstract helpers only if it improves clarity. - **Sample Structure**: ```java @Test public void successfulStoreOnExistingTable() { givenDatabaseConnection(); givenValidConfiguration(); whenWireEnvelopeArrives(); thenEnvelopeIsPersisted(); thenNoErrorsAreReported(); } ``` ## Commit Format - Format: `[optional scope]: ` - Types: - `feat`: add a new feature - `fix`: address a bug - `docs`: documentation-only changes - `refactor`: code change that is neither a feature nor a bug fix - `test`: add or adjust tests - `style`: formatting or stylistic changes with no behavior impact - `chore`: tooling/configuration updates not shipped to production - `build`: build system or dependency changes - `ci`: CI configuration updates - `revert`: revert a previous commit - `perf`: performance improvements - `deprecate`: mark an API as deprecated (include the API name in the description) - Scope: Optional. Use the last segment of the affected bundle name without the `org.eclipse.kura` prefix (e.g., `feat(core.keystore): add key rotation`). - Breaking Changes: Append `!` after the type or scope for breaking changes (e.g., `feat(core.keystore)!: drop legacy cipher`). Provide additional details in the commit body starting with `BREAKING CHANGE:`. ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Community Code of Conduct **Version 1.2 August 19, 2020** ## Our Pledge In the interest of fostering an open and welcoming environment, we as community members, contributors, committers, and project leaders pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities With the support of the Eclipse Foundation staff (the “Staff”), project committers and leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project committers and leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the Eclipse Foundation project or its community in public spaces. Examples of representing a project or community include posting via an official social media account, or acting as a project representative at an online or offline event. Representation of a project may be further defined and clarified by project committers, leaders, or the EMO. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Staff at codeofconduct@eclipse.org. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The Staff is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project committers or leaders who do not follow the Code of Conduct in good faith may face temporary or permanent repercussions as determined by the Staff. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org) , version 1.4, available at [https://www.contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct/) ================================================ FILE: CONTRIBUTING.md ================================================ # How to contribute to Eclipse Kura First of all, thanks for considering to contribute to Eclipse Kura. We really appreciate the time and effort you want to spend helping to improve things around here. And help we can use :-) Here is a (non-exclusive, non-prioritized) list of things you might be able to help us with: * bug reports * bug fixes * improvements regarding code quality e.g. improving readability, performance, modularity etc. * documentation (Getting Started guide, Examples, Deployment instructions in cloud environments) * features (both ideas and code are welcome) * tests In order to get you started as fast as possible we need to go through some organizational issues first. ## Legal Requirements Kura is an [Eclipse IoT](http://iot.eclipse.org) project and as such is governed by the Eclipse Development process. This process helps us in creating great open source software within a safe legal framework. ### First Steps For you as a contributor, the following preliminary steps are required in order for us to be able to accept your contribution: * Sign the [Eclipse Foundation Contributor License Agreement](http://www.eclipse.org/legal/CLA.php). In order to do so: * Obtain an Eclipse Foundation user ID. Anyone who currently uses Eclipse Bugzilla or Gerrit systems already has one of those. If you don't already have an account simply [register on the Eclipse web site](https://dev.eclipse.org/site_login/createaccount.php). * Once you have your account, log in to the [projects portal](https://projects.eclipse.org/), select *My Account* and then the *Contributor License Agreement* tab. * Add your GiHub username to your Eclipse Foundation account. Log in to Eclipse and go to [Edit my account](https://dev.eclipse.org/site_login/myaccount.php). ### File Headers A proper header must be in place for any file contributed to Eclipse Kura. For a new contribution, please add the below header: ``` /******************************************************************************* * Copyright (c) and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * *******************************************************************************/ ``` Please ensure \ is replaced with the current year or range (e.g. 2017 or 2015, 2017). Please ensure \ is replaced with the relevant information. If you are editing an existing contribution, feel free to create or add your legal entity to the contributors section ### How to Contribute The easiest way to contribute code/patches/whatever is by creating a GitHub pull request (PR). When you do make sure that you *Sign-off* your commit records using the same email address used for your Eclipse account. You do this by adding the `-s` flag when you make the commit(s), e.g. $> git commit -s -m "Shave the yak some more" You can find all the details in the [Contributing via Git](http://wiki.eclipse.org/Development_Resources/Contributing_via_Git) document on the Eclipse web site. #### Development Model Development on Eclipse Kura™ follows a [variant of the gitflow model](https://github.com/eclipse/kura/wiki/Kura-Git-Workflow). Development is made on the [develop branch](/eclipse/kura/tree/develop). The master branch is not used anymore. #### Stale PR policy To avoid piling up too many Issues and Pull Requests we enabled a Github Action that takes care of automatically closing stale Issues/Pull Request. - An Issue/Pull Request gets tagged as "_stale_" after **60 days** of inactivity (i.e. no comments/commits etc.) - An Issue/Pull Request gets automatically closed after being "_stale_" for **14 days** without any update Keep this in mind when contributing to the Eclipse Kura project. ## Making your Changes * Fork the repository on GitHub * Create a new branch for your changes * Configure your IDE installing: * The formatter profile available in kura/setup/formatting/KuraFormatter*.xml * The cleanup profile available in kura/setup/formatting/KuraCleanupProfile*.xml * [SonarLint](http://www.sonarlint.org/eclipse/index.html) * Make your changes * Make sure you include test cases for non-trivial features * Make sure the test suite passes after your changes * Make sure copyright headers are included in (all) files including updated year(s) * Make sure build plugins and dependencies and their versions have (approved) CQs * Make sure proper headers are in place for each file (see above Legal Requirements) * Commit your changes into that branch * Use descriptive and meaningful commit messages * If you have a lot of commits squash them into a single commit * Make sure you use the `-s` flag when committing as explained above * Push your changes to your branch in your forked repository * Make a full clean build (locally and/or using [Travis CI](http://travis-ci.org)) before you submit a pull request ## Tests Eclipse Kura since 5.1.0 version only accepts tests made following Gherkin format. Extend the old tests files is still allowed but not creating new ones. ### Gherkin Tests Guidelines Gherkin is a particular language that originates from Behavioral-Driven Development (BDD). In BDD, the developer defines tests that will guide the development and constitute a requirement. The tests are written by first defining the **feature** that is going to be tested, then defining the most relevant execution paths for that feature, called **scenarios**, and, finally, detailing the scenarios into simple **steps** using Gherkin language. ### Features Every Gherkin test should test a specific feature. Every tested feature is contained in a single test class. An example of feature for the H2DbWireStoreComponent can be *“Store wire envelopes“* and the corresponding test class will be StoreWireEnvelopeTest.java. Guidelines for defining features: - group features for a specific component in the same test package - if it is not easy to define a simple name that describes the feature, then maybe it is too complicated and needs to be split into multiple features - if the tested component is simple, then use the existing naming convention: ComponentNameTest ### Scenarios Scenarios break down the single feature into steps. Each scenario covers a path of execution for that feature and is identified by a method inside the feature class. As an example for the H2DbStoreComponent, one can think of a scenario *“Successful store data“* which will correspond to the method successfulStore(), but also of a scenario that should cause an error like *“Store in a DB table that does not exist“*. Guidelines for defining scenarios: - try to define also the unhappy paths, i.e. paths that cause errors - methods that define scenarios do not return values, do not have parameters, and should be annotated with JUnit’s @Test annotation - the method name should describe the scenario as better as possible; no comments should be needed to understand it; else, break it down into multiple ones - no nested scenarios - scenarios should be placed on top of the class, it is the first and only thing that a developer should read to understand the test ### Steps Steps detail scenarios further. Scenarios contain multiple steps that follow a specific pattern. Steps can be defined using one of these keywords: ***given - when - then*** - **given** defines the test preconditions, an initial context - **when** defines the actions performed, or events - **then** describes the effects, the expected outcome Guidelines for defining steps: - step methods must be private and separated from the scenarios: public scenarios on top, private steps on the bottom - steps inside a scenario always follow the *given-when-then* order - step methods names must start with one of the keywords - there can be multiple steps of the same kind inside a single scenario, i.e. 3 given, 1 when, 2 then; to improve readability separate them with a blank line to form a group for the *given* steps, one for the *when* steps, and one for the *then* steps - steps can take arguments - steps do not return values - step methods contain asserts Example of a scenario with steps: ```java @Test public void storeOnNotExistentTable() { givenDatabaseConnection(); givenConfigurationWithWrongTableName(); whenWireEnvelopeArrives(); thenThrowException(); thenDataNotStored(); } ``` ### Internal State and Helpers Since step and scenario methods are not allowed to return any value, it is sometimes necessary to maintain an **internal state** inside the feature class. Where the tested features require complex dependencies, it might be useful to define an **abstract helper class** which will be inherited by all the feature classes. The Gherkin reference: https://cucumber.io/docs/gherkin/reference/ ### Manual Tests Before you submit a Pull Request, ensure that your changes have been tested and are functional in a live environment. If you require additional validation, kindly request your reviewer to perform the necessary tests. It is strongly recommended that you personally verify your changes before submission and only seek further testing when absolutely necessary. ## Submitting the Changes Submit a pull request via the normal GitHub UI. We are using the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) convention for our pull request titles. This convention dovetails with [SemVer](https://semver.org/), by describing the features, fixes, and breaking changes made in commit messages. Every PR which is not in draft mode should follow conventional commit convention for PR title. Therefore the title should be in the format: ``` [optional scope]: ``` Where: - `` - see [_Type_ section](#type) - `[optional scope]` - see [_Scope_ section](#scope) - `` - description of the PR **BREAKING CHANGE:** a commit that appends a `!` after the type/scope, introduces a breaking API change. A BREAKING CHANGE can be part of commits of any _type_. Once merged and squashed in the main development branch, the resulting commit message should match the PR title. For details see the [full specification](https://www.conventionalcommits.org/en/v1.0.0/#specification). ### Type 1. The type `feat` MUST be used when a commit adds a new feature to your application or library. 2. The type `fix` MUST be used when a commit represents a bug fix for your application. Types other than `feat` and `fix` MAY be used in your commit messages and must be one of the following: - `docs`: Documentation only changes - `refactor`: A code change that neither fixes a bug nor adds a feature (removing redundant code, code semplification, renaming variables, removing features, etc) - `test`: Adding missing tests or correcting existing tests - `style`: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) - `chore`: Tool changes, configuration changes, and changes to things that do not actually go into production at all (upticks/bumps, manual update of release notes...) - `build`: Changes that affect the build system or external dependencies (dependencies update) - `ci`: Changes to our CI configuration files and scripts - `revert`: Reverts a previous commit - `perf`: A code change that improves performance - `deprecate`: An API/component deprecation. Use the summary field to provide the API/component which was deprecated (eg: `deprecate: org.eclipse.kura.position.PositionService`) ### Scope A scope MAY be provided after a type. A scope MUST consist of a noun describing a section of the codebase surrounded by parenthesis, e.g., `fix(parser):` The scope should describe the section of the code affected by the changes as perceived by the person reading the changelog generated from commit messages. As a general rule use the last part of the bundle name as the scope (i.e. without `org.eclipse.kura`). If the PR spans across multiple bundles use the main one or do not fill the scope at all. Example: if a PR adds a feature to the `org.eclipse.kura.core.keystore` bundle, the PR title shoud be `feat(core.keystore): new awesome feature`. ## After Submitting * Do not use your branch for any other development, otherwise further changes that you make will be visible in the PR. ================================================ FILE: Jenkinsfile ================================================ import org.jenkinsci.plugins.pipeline.modeldefinition.Utils def boolean onlyDocumentationFilesChangedIn(String workDirectory) { if (!env.CHANGE_TARGET) { echo "CHANGE_TARGET not set. Skipping check" return false } def changedFiles = sh(script: "cd ${workDirectory} && git diff --name-only origin/${env.CHANGE_TARGET} origin/${env.BRANCH_NAME}", returnStdout: true).trim().split("\n") echo "Changed files: ${changedFiles}" // Debug return changedFiles && changedFiles.every { it.endsWith(".md") || it.endsWith(".txt") } } node { properties([ disableConcurrentBuilds(abortPrevious: true), buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '1', daysToKeepStr: '', numToKeepStr: '3')), gitLabConnection('gitlab.eclipse.org'), [$class: 'RebuildSettings', autoRebuild: false, rebuildDisabled: false], [$class: 'JobLocalConfiguration', changeReasonComment: ''] ]) deleteDir() stage('Preparation') { dir("kura") { checkout scm sh "touch /tmp/isJenkins.txt" } } // Skip build if only documentation files (i.e. *.md and *.txt) have changed if (onlyDocumentationFilesChangedIn("kura")) { echo "Skipping build for documentation changes" currentBuild.result = 'SUCCESS' return } stage('Build target-platform') { timeout(time: 1, unit: 'HOURS') { dir("kura") { withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) { sh "mvn -f target-platform/pom.xml clean install -Pno-mirror -Pcheck-exists-plugin" } } } } stage('Build core') { timeout(time: 2, unit: 'HOURS') { dir("kura") { withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) { sh "mvn -f kura/pom.xml -Dsurefire.rerunFailingTestsCount=3 clean install -Pcheck-exists-plugin" } } } } stage('Build distrib') { timeout(time: 1, unit: 'HOURS') { dir("kura") { withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) { sh "mvn -f kura/distrib/pom.xml clean install" } } } } stage('Generate test reports') { dir("kura") { junit 'kura/test/*/target/surefire-reports/*.xml' } } stage ("Deploy on Nexus") { // Call uploadPackages only if we are on the default branch, // if we have DEB packages to upload and if the user has set the pushArtifacts parameter to true if (env.BRANCH_IS_PRIMARY) { echo "Uploading DEB packages..." def distribPom = readMavenPom file: 'kura/kura/distrib/pom.xml' def repoDistribution = distribPom.properties['kura.repo.distribution'] def repoModule = distribPom.properties['kura.repo.module'] def nexusUtils = load 'kura/.jenkins/nexusUtils.groovy' nexusUtils.uploadPackages(repoDistribution, repoModule) } else { echo "Skipping DEB upload" Utils.markStageSkippedForConditional(STAGE_NAME) } } stage('Archive .deb artifacts') { dir("kura") { archiveArtifacts artifacts: 'kura/distrib/**/target/*.deb', onlyIfSuccessful: true } } stage('Sonar') { timeout(time: 2, unit: 'HOURS') { dir("kura") { withMaven(jdk: 'temurin-jdk21-latest', maven: 'apache-maven-3.9.9', options: [artifactsPublisher(disabled: true)]) { withSonarQubeEnv(credentialsId: 'sonarcloud-token') { // Check if on primary branch def analysisParameters = "" if (env.CHANGE_ID) { analysisParameters = "-Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} -Dsonar.pullrequest.base=${env.CHANGE_TARGET} -Dsonar.pullrequest.key=${env.CHANGE_ID}" } else { analysisParameters = "-Dsonar.branch.name=${env.BRANCH_NAME}" } sh """ mvn -f kura/pom.xml org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ -Dmaven.test.failure.ignore=true \ -Dsonar.organization=eclipse \ -Dsonar.host.url=${SONAR_HOST_URL} \ -Dsonar.java.binaries='target/' \ ${analysisParameters} \ -Dsonar.core.codeCoveragePlugin=jacoco \ -Dsonar.projectKey=org.eclipse.kura:kura \ -Dsonar.exclusions=test/**/*,**/*.xml,**/*.yml,test-util/**/* \ -Dsonar.test.exclusions=**/* """ } } } } } stage('quality-gate') { // Sonar quality gate timeout(time: 30, unit: 'MINUTES') { withCredentials([string(credentialsId: 'sonarcloud-token', variable: 'SONARCLOUD_TOKEN')]) { def qg = waitForQualityGate() if (qg.status != 'OK') { error "Pipeline aborted due to sonar quality gate failure: ${qg.status}" } } } } } ================================================ FILE: LICENSE ================================================ Eclipse Public License - v 2.0 THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. 1. DEFINITIONS "Contribution" means: a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and b) in the case of each subsequent Contributor: i) changes to the Program, and ii) additions to the Program; where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution "originates" from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works. "Contributor" means any person or entity that Distributes the Program. "Licensed Patents" mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program. "Program" means the Contributions Distributed in accordance with this Agreement. "Recipient" means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors. "Derivative Works" shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. "Modified Works" shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof. "Distribute" means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy. "Source Code" means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files. "Secondary License" means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor. 2. GRANT OF RIGHTS a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works. b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder. c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program. d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement. e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3). 3. REQUIREMENTS 3.1 If a Contributor Distributes the Program in any form, then: a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license: i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose; ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits; iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3. 3.2 When the Program is Distributed as Source Code: a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and b) a copy of this Agreement must be included with each copy of the Program. 3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability ("notices") contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices. 4. COMMERCIAL DISTRIBUTION Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor ("Commercial Contributor") hereby agrees to defend and indemnify every other Contributor ("Indemnified Contributor") against any losses, damages and costs (collectively "Losses") arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense. For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages. 5. NO WARRANTY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. 6. DISCLAIMER OF LIABILITY EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. GENERAL If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed. All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive. Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version. Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement. Exhibit A - Form of Secondary Licenses Notice "This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}." Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. ================================================ FILE: NOTICE.md ================================================ # Notices for Eclipse Kura This content is produced and maintained by the Eclipse Kura project. * Project home: https://projects.eclipse.org/projects/iot.kura ## Trademarks Eclipse Kura, and Kura are trademarks of the Eclipse Foundation. ## Copyright All content is the property of the respective authors or their employers. For more information regarding authorship of content, please consult the listed source code repository logs. ## Declared Project Licenses This program and the accompanying materials are made available under the terms of the Eclipse Public License v2.0 which is available at https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html. SPDX-License-Identifier: EPL-2.0 ## Source Code The project maintains the following source code repositories: * https://github.com/eclipse/kura * https://github.com/eclipse/kura-apps ## Third-party Content This project leverages the following third party content. ### Maven Dependencies * maven/mavencentral/com.eclipsesource.minimal-json/minimal-json/0.9.5, MIT, approved, CQ10061 * maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.19.1, Apache-2.0, approved, #21911 * maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.19.1, Apache-2.0 AND MIT, approved, #21916 * maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.19.1, Apache-2.0, approved, #21909 * maven/mavencentral/com.github.docker-java/docker-java-api/3.5.3, Apache-2.0, approved, #22668 * maven/mavencentral/com.github.docker-java/docker-java-core/3.5.3, Apache-2.0, approved, #22665 * maven/mavencentral/com.github.docker-java/docker-java-transport-httpclient5/3.5.3, Apache-2.0, approved, #22669 * maven/mavencentral/com.github.docker-java/docker-java-transport/3.5.3, Apache-2.0, approved, #22667 * maven/mavencentral/com.github.docker-java/docker-java/3.5.3, Apache-2.0, approved, #22666 * maven/mavencentral/com.github.rodionmoiseev.c10n/c10n-core/1.2, Apache-2.0, approved, clearlydefined * maven/mavencentral/com.google.code.gson/gson/2.9.0, Apache-2.0, approved, CQ24148 * maven/mavencentral/com.google.guava/guava/32.1.1-jre, Apache-2.0, approved, clearlydefined * maven/mavencentral/com.google.guava/failureaccess/1.0.1, Apache-2.0, approved, clearlydefined * maven/mavencentral/com.google.protobuf/protobuf-java/3.19.3, BSD-3-Clause, approved, clearlydefined * maven/mavencentral/com.h2database/h2/2.4.240, EPL-1.0 AND MPL-2.0 AND LGPL-2.1-or-later AND BSD-3-Clause AND LicenseRef-Public-Domain, approved, #23567 * maven/mavencentral/com.sun.xml.bind/jaxb-osgi/2.3.3, BSD-3-Clause, approved, ee4j.jaxb-impl * maven/mavencentral/com.vertispan.j2cl.external/org.eclipse.core.jobs/0.10.0-3c97afeac, EPL-2.0, approved, eclipse.platform * maven/mavencentral/com.vertispan.j2cl.external/org.eclipse.equinox.preferences/0.10.0-3c97afeac, EPL-2.0, approved, #7856 * maven/mavencentral/commons-codec/commons-codec/1.16.1, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #9157 * maven/mavencentral/org.apache.commons/commons-fileupload2-core/2.0.0-M2, Apache-2.0, approved, #15738 * maven/mavencentral/org.apache.commons/commons-fileupload2-jakarta-servlet5/2.0.0-M2, Apache-2.0, approved, #15737 * maven/mavencentral/commons-io/commons-io/2.19.0, Apache-2.0, approved, #20657 * maven/mavencentral/commons-net/commons-net/3.8.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/io.netty/netty-all/4.1.130.Final, Apache-2.0 AND MIT AND BSD-3-Clause AND CC0-1.0 AND LicenseRef-Public-Domain, approved, CQ22582 * maven/mavencentral/io.netty/netty-buffer/4.1.130.Final, Apache-2.0, approved, CQ21842 * maven/mavencentral/io.netty/netty-codec-http/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-codec-mqtt/4.1.130.Final, Apache-2.0 OR LicenseRef-Public-Domain OR BSD-2-Clause OR MIT, approved, CQ15280 * maven/mavencentral/io.netty/netty-codec/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-common/4.1.130.Final, Apache-2.0 AND MIT AND CC0-1.0, approved, CQ21843 * maven/mavencentral/io.netty/netty-handler/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-resolver/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-transport-classes-epoll/4.1.130.Final, Apache-2.0, approved, clearlydefined * maven/mavencentral/io.netty/netty-transport-classes-kqueue/4.1.130.Final, Apache-2.0, approved, #4107 * maven/mavencentral/io.netty/netty-transport-native-epoll/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-transport-native-kqueue/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-transport/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-codec-socks/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.netty/netty-handler-proxy/4.1.130.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 * maven/mavencentral/io.perfmark/perfmark-api/0.26.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/jakarta.activation/jakarta.activation-api/1.2.2, EPL-2.0 OR BSD-3-Clause OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jaf * maven/mavencentral/jakarta.xml.bind/jakarta.xml.bind-api/2.3.3, BSD-3-Clause, approved, ee4j.jaxb * maven/mavencentral/jakarta.xml.soap/jakarta.xml.soap-api/1.4.2, , approved, eclipse * maven/mavencentral/jakarta.xml.ws/jakarta.xml.ws-api/2.3.3, , approved, eclipse * maven/mavencentral/net.java.dev.jna/jna/5.8.0, Apache-2.0 OR LGPL-2.1-or-later, approved, CQ23217 * maven/mavencentral/org.apache.camel/camel-amqp/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.camel/camel-core-osgi/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.camel/camel-core/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.camel/camel-jms/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.camel/camel-script/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.camel/camel-stream/2.25.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.commons/commons-compress/1.27.1, Apache-2.0 AND (Apache-2.0 AND BSD-3-Clause), approved, #17651 * maven/mavencentral/org.apache.commons/commons-csv/1.4, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.commons/commons-exec/1.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.commons/commons-lang3/3.19.0, Apache-2.0, approved, #23560 * maven/mavencentral/org.apache.felix/org.apache.felix.dependencymanager/3.0.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.felix/org.apache.felix.deploymentadmin/0.9.5, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.geronimo.specs/geronimo-jms_2.0_spec/1.0-alpha-2, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.httpcomponents.core5/httpcore5-h2/5.3.4, Apache-2.0, approved, #16867 * maven/mavencentral/org.apache.httpcomponents.client5/httpclient5/5.0.3, Apache-2.0 and MIT, approved, CQ23948 * maven/mavencentral/org.apache.httpcomponents.core5/httpcore5/5.0.2, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.logging.log4j/log4j-api/2.25.3, Apache-2.0, approved, #21940 * maven/mavencentral/org.apache.logging.log4j/log4j-core/2.25.3, Apache-2.0 AND (Apache-2.0 AND LGPL-2.0-or-later), approved, #21939 * maven/mavencentral/org.apache.logging.log4j/log4j-slf4j2-impl/2.25.3, Apache-2.0, approved, #21938 * maven/mavencentral/org.apache.qpid/proton-j/0.33.2, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.qpid/qpid-jms-client/0.45.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-beans/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16239 * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-context/4.3.20.RELEASE_1, , approved, CQ16240 * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-core/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16241 * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-expression/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16242 * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-jms/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16243 * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.spring-tx/4.3.20.RELEASE_1, Apache-2.0, approved, CQ16244 * maven/mavencentral/org.bouncycastle/bcpg-jdk18on/1.78.1, Apache-2.0, approved, #14432 * maven/mavencentral/org.bouncycastle/bcpkix-jdk18on/1.78.1, MIT, approved, #14434 * maven/mavencentral/org.bouncycastle/bcprov-jdk18on/1.78.1, MIT AND CC0-1.0, approved, #14433 * maven/mavencentral/org.bouncycastle/bctls-jdk18on/1.78.1, MIT, approved, #14676 * maven/mavencentral/org.bouncycastle/bcutil-jdk18on/1.78.1, MIT, approved, #14435 * maven/mavencentral/org.eclipse.milo/sdk-client/0.6.8, EPL-2.0, approved, iot.milo * maven/mavencentral/org.eclipse.milo/sdk-core/0.6.8, EPL-2.0, approved, iot.milo * maven/mavencentral/org.eclipse.milo/stack-client/0.6.8, EPL-2.0, approved, iot.milo * maven/mavencentral/org.eclipse.milo/stack-core/0.6.8, EPL-2.0, approved, iot.milo * maven/mavencentral/org.glassfish.hk2/osgi-resource-locator/1.0.3, CDDL-1.0, approved, CQ10889 * maven/mavencentral/org.knowhowlab.osgi/monitoradmin/1.0.3, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.osgi/osgi.annotation/8.1.0, Apache-2.0, approved, #1985 * maven/mavencentral/org.quartz-scheduler/quartz/2.5.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.slf4j/jcl-over-slf4j/2.0.17, MIT AND Apache-2.0, approved, #11889 * maven/mavencentral/org.slf4j/slf4j-api/2.0.17, MIT, approved, #5915 * maven/mavencentral/org.slf4j/jul-to-slf4j/2.0.17, MIT, approved, #7698 * maven/mavencentral/org.usb4java/libusb4java/1.3.0, MIT, approved, #3087 * maven/mavencentral/org.usb4java/usb4java-javax/1.3.0, MIT, approved, #22528 * maven/mavencentral/org.usb4java/usb4java/1.3.0, MIT, approved, clearlydefined * maven/mavencentral/org.apache.servicemix.bundles/org.apache.servicemix.bundles.c3p0/0.9.5.5_1, Apache-2.0, approved, #3761 * maven/mavencentral/com.zaxxer/HikariCP/2.7.9, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.xerial/sqlite-jdbc/3.42.0.0, Apache-2.0 AND BSD-2-Clause AND ISC AND Artistic-2.0, approved, #9089 * maven/mavencentral/org.graalvm.js/js/21.3.9, UPL-1.0 AND (UPL-1.0 AND GPL-2.0-only WITH Classpath-exception-2.0) AND BSD-3-Clause AND MPL-2.0, approved, #6714 * maven/mavencentral/org.graalvm.js/js-scriptengine/21.3.9, UPL-1.0, approved, #6715 * maven/mavencentral/org.graalvm.js/js-launcher/21.3.9, UPL-1.0, approved, #6716 * maven/mavencentral/org.graalvm.sdk/graal-sdk/21.3.9, UPL-1.0, approved, #6717 * maven/mavencentral/org.graalvm.truffle/truffle-api/21.3.9, UPL-1.0, approved, #6718 * maven/mavencentral/org.graalvm.regex/regex/21.3.9, UPL-1.0 AND Unicode-TOU, approved, #6719 * maven/mavencentral/org.graalvm.sdk/launcher-common/21.3.9, UPL-1.0, approved, #6720 * maven/mavencentral/com.ibm.icu/icu4j/72.1, ICU, approved, #4354 * maven/mavencentral/com.github.hypfvieh/dbus-java/3.3.2, MIT, approved, CQ23190 * maven/mavencentral/com.github.jnr/jffi/1.3.9, Apache-2.0 OR LGPL-3.0-or-later, approved, CQ23196 * maven/mavencentral/com.github.jnr/jnr-a64asm/1.0.0, Apache-2.0, approved, CQ22814 * maven/mavencentral/com.github.jnr/jnr-constants/0.10.3, Apache-2.0, approved, CQ23193 * maven/mavencentral/com.github.jnr/jnr-enxio/0.32.13, Apache-2.0, approved, CQ23194 * maven/mavencentral/com.github.jnr/jnr-ffi/2.2.11, Apache-2.0, approved, CQ23192 * maven/mavencentral/com.github.jnr/jnr-posix/3.1.15, EPL-2.0 OR GPL-2.0-only OR LGPL-2.1-only, approved, #2711 * maven/mavencentral/com.github.jnr/jnr-unixsocket/0.38.17, Apache-2.0, approved, CQ23191 * maven/mavencentral/com.github.jnr/jnr-x86asm/1.0.2, MIT, approved, CQ9094 * maven/mavencentral/org.ow2.asm/asm-analysis/9.2, BSD-3-Clause, approved, clearlydefined * maven/mavencentral/org.ow2.asm/asm-commons/9.2, BSD-3-Clause, approved, clearlydefined * maven/mavencentral/org.ow2.asm/asm-tree/9.2, BSD-3-Clause, approved, clearlydefined * maven/mavencentral/org.ow2.asm/asm-util/9.2, BSD-3-Clause, approved, clearlydefined * maven/mavencentral/org.ow2.asm/asm/9.2, BSD-3-Clause, approved, CQ23635 * maven/mavencentral/com.google.guava/guava/31.0-jre, Apache-2.0, approved, clearlydefined * maven/mavencentral/com.google.guava/failureaccess/1.0, Apache-2.0, approved, CQ22654 * maven/mavencentral/com.digitalpetri.fsm/strict-machine/0.6, Apache-2.0, approved, clearlydefined * maven/mavencentral/com.digitalpetri.netty/netty-channel-fsm/0.8, Apache-2.0, approved, #6168 * maven/mavencentral/jakarta.annotation/jakarta.annotation-api/2.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.ca * maven/mavencentral/org.apache.felix/org.apache.felix.http.servlet-api/3.0.0, Apache-2.0, approved, #13345 * maven/mavencentral/org.apache.felix/org.apache.felix.http.bridge/5.1.8, Apache-2.0, approved, #18536 * maven/mavencentral/org.apache.felix/org.apache.felix.http.proxy/4.0.0, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.apache.felix/org.apache.felix.http.wrappers/1.1.2, Apache-2.0, approved, clearlydefined * maven/mavencentral/org.eclipse.jetty/jetty-http/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty/jetty-security/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty/jetty-server/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty/jetty-session/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty/jetty-util/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty/jetty-io/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.eclipse.jetty.ee10/jetty-ee10-servlet/12.0.14, EPL-2.0 OR Apache-2.0, approved, rt.jetty * maven/mavencentral/org.osgi/org.osgi.service.http.whiteboard/1.1.1, Apache-2.0, approved, #5518 * maven/mavencentral/org.osgi/org.osgi.service.servlet/2.0.0, Apache-2.0, approved, #5264 * maven/mavencentral/jakarta.ws.rs/jakarta.ws.rs-api/3.1.0, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.rest * maven/mavencentral/org.osgi/org.osgi.service.jakartars/2.0.0, Apache-2.0, approved, #4692 * maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest/1.2.3, Apache-2.0, approved, technology.osgi-technology * maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest.sse/1.2.3, Apache-2.0, approved, technology.osgi-technology * maven/mavencentral/org.eclipse.osgi-technology.rest/org.eclipse.osgitech.rest.servlet.whiteboard/1.2.3, Apache-2.0, approved, technology.osgi-technology * maven/mavencentral/org.apache.aries.spifly/org.apache.aries.spifly.dynamic.bundle/1.3.7, Apache-2.0, approved, #15243 * maven/mavencentral/org.ow2.asm/asm/9.7.1, BSD-3-Clause, approved, #16464 * maven/mavencentral/org.ow2.asm/asm-commons/9.7.1, BSD-3-Clause, approved, #16465 * maven/mavencentral/org.ow2.asm/asm-tree/9.7.1, BSD-3-Clause, approved, #16466 * maven/mavencentral/org.ow2.asm/asm-util/9.7.1, BSD-3-Clause, approved, #16467 * maven/mavencentral/org.ow2.asm/asm-analysis/9.7.1, BSD-3-Clause, approved, #16463 * maven/mavencentral/org.glassfish.hk2/hk2-api/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish * maven/mavencentral/org.glassfish.hk2.external/aopalliance-repackaged/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish * maven/mavencentral/org.glassfish.hk2/hk2-locator/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish * maven/mavencentral/org.glassfish.hk2/hk2-utils/3.1.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.glassfish * maven/mavencentral/org.glassfish.jersey.inject/jersey-hk2/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.containers/jersey-container-servlet-core/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.core/jersey-client/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.core/jersey-common/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.core/jersey-server/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.ext/jersey-entity-filtering/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.media/jersey-media-jaxb/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.media/jersey-media-sse/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/org.glassfish.jersey.media/jersey-media-multipart/3.1.11, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jersey * maven/mavencentral/jakarta.inject/jakarta.inject-api/2.0.1, Apache-2.0, approved, ee4j.cdi * maven/mavencentral/jakarta.validation/jakarta.validation-api/3.0.2, Apache-2.0, approved, ee4j.validation * maven/mavencentral/org.javassist/javassist/3.30.2-GA, Apache-2.0 AND LGPL-2.1-or-later AND MPL-1.1, approved, #12108 * maven/mavencentral/org.jvnet.mimepull/mimepull/1.10.0, BSD-3-Clause, approved, #2699 * maven/mavencentral/org.apache.felix/org.apache.felix.gogo.command/1.1.2, Apache-2.0, approved, #17675 * maven/mavencentral/org.apache.felix/org.apache.felix.gogo.runtime/1.1.6, Apache-2.0 AND MIT, approved, CQ22929 * maven/mavencentral/org.apache.felix/org.apache.felix.scr/2.2.12, Apache-2.0, approved, #15367 * maven/mavencentral/org.eclipse.platform/org.eclipse.core.contenttype/3.9.500, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.core.jobs/3.15.400, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.core.runtime/3.31.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.app/1.7.200, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.cm/1.6.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.common/3.19.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.console/1.4.800, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.event/1.7.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.io/1.1.300, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.launcher/1.6.900, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.metatype/1.6.600, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.preferences/3.11.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.registry/3.12.100, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.util/1.1.300, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.equinox.wireadmin/1.0.800, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.osgi.util/3.7.300, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.eclipse.platform/org.eclipse.osgi/3.21.0, EPL-2.0, approved, eclipse.platform * maven/mavencentral/org.osgi/org.osgi.service.cm/1.6.1, Apache-2.0, approved, #18262 * maven/mavencentral/org.osgi/org.osgi.service.component/1.5.1, Apache-2.0, approved, #5389 * maven/mavencentral/org.osgi/org.osgi.service.coordinator/1.0.2, Apache-1.1 AND Apache-2.0, approved, #17662 * maven/mavencentral/org.osgi/org.osgi.service.device/1.1.1, Apache-2.0, approved, #15335 * maven/mavencentral/org.osgi/org.osgi.service.event/1.4.1, Apache-2.0, approved, #15500 * maven/mavencentral/org.osgi/org.osgi.service.log.stream/1.0.0, Apache-2.0, approved, #2442 * maven/mavencentral/org.osgi/org.osgi.service.metatype/1.4.1, Apache-2.0, approved, #15382 * maven/mavencentral/org.osgi/org.osgi.service.prefs/1.1.2, Apache-2.0, approved, #15379 * maven/mavencentral/org.osgi/org.osgi.service.provisioning/1.2.0, Apache-1.1 AND Apache-2.0, approved, #17681 * maven/mavencentral/org.osgi/org.osgi.service.upnp/1.2.1, Apache-2.0, approved, #15268 * maven/mavencentral/org.osgi/org.osgi.service.useradmin/1.1.1, Apache-2.0, approved, #15323 * maven/mavencentral/org.osgi/org.osgi.service.wireadmin/1.0.2, Apache-2.0, approved, #15398 * maven/mavencentral/org.osgi/org.osgi.util.function/1.2.0, Apache-2.0, approved, #15222 * maven/mavencentral/org.osgi/org.osgi.util.measurement/1.0.2, Apache-2.0, approved, #17679 * maven/mavencentral/org.osgi/org.osgi.util.position/1.0.1, Apache-1.1 AND Apache-2.0, approved, #17683 * maven/mavencentral/org.osgi/org.osgi.util.promise/1.3.0, Apache-2.0, approved, #5266 * maven/mavencentral/org.osgi/org.osgi.util.pushstream/1.1.0, Apache-2.0, approved, #6026 * maven/mavencentral/org.osgi/org.osgi.util.xml/1.0.2, Apache-2.0, approved, #15377 * maven/mavencentral/com.fasterxml.jackson.core/jackson-databind/2.19.2, Apache-2.0, approved, #21909 * maven/mavencentral/com.fasterxml.jackson.core/jackson-annotations/2.19.2, Apache-2.0, approved, #21911 * maven/mavencentral/com.fasterxml.jackson.core/jackson-core/2.19.2, Apache-2.0 AND MIT, approved, #21916 ### Additional Dependencies * maven/mavencentral/javax.usb/usb-api/1.0.2, MIT, approved, CQ7834 * javax.el_2.2.0.v201303151357, EPL-2.0, approved, eclipse.platform * org.tigris.mtoolkit.iagent.rpc_3.0.0.20110411-0918, EPL-1.0, approved, CQ7880 * com.codeminders.hidapi natives 1.1, New BSD License, approved, CQ7871 * soda.dk.comm, EPL-1.0, approved, CQ8156 * org.hamcrest.core 1.1, New BSD License, approved, CQ7842 * org.apache.felix.useradmin_1.0.4.k1, Apache-2.0, approved, CQ23078 * com.codeminders.hidapi 1.1, New BSD License, approved, CQ7833 * org.moka7 1.0.2, EPL-1.0, approved, CQ12777 * org.eclipse.paho.client.mqttv3 1.2.1.k2, EPL-1.0, approved, eclipse.platform ## Cryptography Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. ================================================ FILE: PULL_REQUEST_TEMPLATE.md ================================================ > **Note**: We are using the Conventional Commits convention for our pull request titles. Please take a look at the [PR title format document](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#submitting-the-changes) for the supported [types](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#type) and [scopes](https://github.com/eclipse/kura/blob/develop/CONTRIBUTING.md#scope). Brief description of the PR. [e.g. Added `null` check on `object` to avoid `NullPointerException`] **Related Issue:** This PR fixes/closes {issue number} **Description of the solution adopted:** A more detailed description of the changes made to solve/close one or more issues. If the PR is simple and easy to understand this section can be skipped **Screenshots:** If applicable, add screenshots to help explain your solution **Manual Tests**: Optional description of the tests performed to check correct functioning of changes, useful for an efficient review **Any side note on the changes made:** Description of any other change that has been made, which is not directly linked to the issue resolution [e.g. Code clean up/Sonar issue resolution] ================================================ FILE: README.md ================================================ Eclipse Kura™ =============

Kura™ logo

[![GitHub](https://img.shields.io/github/license/eclipse/kura?label=License)](https://github.com/eclipse-kura/kura/blob/develop/LICENSE) [![Jenkins](https://img.shields.io/jenkins/build?jobUrl=https:%2F%2Fci.eclipse.org%2Fkura%2Fjob%2Fmultibranch%2Fjob%2Fdevelop&label=Jenkins%20Build&logo=jenkins)](https://ci.eclipse.org/kura/job/multibranch/job/develop/) [![Jenkins](https://img.shields.io/jenkins/tests?compact_message&failed_label=%E2%9D%8C&jobUrl=https:%2F%2Fci.eclipse.org%2Fkura%2Fjob%2Fmultibranch%2Fjob%2Fdevelop%2F&label=Jenkins%20CI&passed_label=%E2%9C%85&skipped_label=%E2%9D%95&logo=jenkins)](https://ci.eclipse.org/kura/job/multibranch/)
## What is Eclipse Kura™? From [the maori word for tank/container](https://maoridictionary.co.nz/search/?keywords=kura), Eclipse Kura™ is a versatile software framework designed to supercharge your edge devices. With an intuitive web interface, Eclipse Kura™ streamlines the process of configuring your gateway, connecting sensors, and IoT devices to seamlessly collect, process, and send data to the cloud. Eclipse Kura™ provides an extensible Java API for developing custom plugins within the framework. Additionally, it offers a REST API, enabling the use of Eclipse Kura™ as a backend service in your application. Eclipse Kura™ runs on an edge gateway, which can be anything from a small SBC(single-board computer) like a Raspberry Pi, or a powerful high-performance computer. ### What can Eclipse Kura™ do for me? * **Kura™ Services:** Provision and set up features to run on your gateway, such as an MQTT broker. * **Kura™ Networking:** Manage Network connectivity, including * **Kura™ Wires:** Design data flows and data processing streams effortlessly with a drag-and-drop visual editor. * **Kura™ Cloud Connectors:** Extendable cloud connector system. * **Kura™ Drivers:** Extendable service that handles reading data off of external devices. * **Kura™ Snapshots:** Securely store and re-apply gateway settings for convenience. * **Kura™ Security**: Easily and safely store your secrets. * **Kura™ Container Orchestrator**: Manage Docker or Podman containers on your gateway for ultimate flexibility. * **Kura™ AI Inference**: Run Nvidia Triton Models on the edge. * **Kura™ Plugins**: Add and Extend the framework by adding your own Services, and Drivers. * **Kura™ REST Service**: Embed the framework as a backend in your own edge applications. ### I have used Eclipse Kura™ to make a small-scale Edge deployment, how do I scale now? If you want to scale, and manage many instances of Eclipse Kura™, check out [**Eclipse Kapua™**](https://github.com/eclipse/kapua). [Eclipse Kapua™](https://github.com/eclipse/kapua) is a Eclipse Kura™ compatible cloud command and control service that allows you to aggregate data and configure many Eclipse Kura™ devices. Documentation ------------------- - [**User Documentation**](https://eclipse-kura.github.io/kura/latest/): here you'll find information on how to **use** Eclipse Kura™ i.e. installation instructions, informations on how to use the web UI and tutorials. - [**Developer Documentation**](https://github.com/eclipse-kura/kura/wiki): the Eclipse Kura™ Github Wiki serves as a reference for **developers** who want to contribute to the Eclipse Kura™ project and/or develop new add-ons. Here you'll find Eclipse Kura™ development/release model, guidelines on how to import internal packages, creating new bundles and development environment tips & tricks. - [**Docker Containers Documentation**](https://hub.docker.com/r/eclipsekura/kura/): the Eclipse Kura™ team also provides Docker containers for the project. Information on how to build and run them are available at https://github.com/eclipse-kura/kura-metapackage. - [**Developer Quickstart Guide**](https://github.com/eclipse-kura/kura#build): a quick guide on how to setup the development environment and build the project is also provided in this README. Additionally, we provide two channels for reporting any issue you find with the project - [**Github Issues**](https://github.com/eclipse-kura/kura/issues): for bug reporting. - [**Github Discussions**](https://github.com/eclipse-kura/kura/discussions): for receiving feedback, asking questions, making new proposals and generally talking about the project. Install ------- Eclipse Kura™ is compatible with Java 21. ### Quick Linux installation The APT repository provides packages for both **x86‑64** and **arm64** architectures. To install the latest stable version of **Eclipse Kura™**, run the following commands in a terminal: ```bash # Install required tools sudo apt update sudo apt install -y curl gpg # Add the Eclipse Kura APT repository key curl -fsSL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xBA7E3DF5EDC3FC36" \ | gpg --dearmor \ | sudo tee /etc/apt/keyrings/kura.gpg > /dev/null # Add the Eclipse Kura APT repository sudo tee /etc/apt/sources.list.d/kura.sources > /dev/null << 'EOF' Types: deb URIs: https://repo.eclipse.org/repository/kura-apt/ Suites: stable Components: main Signed-By: /etc/apt/keyrings/kura.gpg EOF # Update package index and install Eclipse Kura sudo apt update sudo apt install -y kura ``` > **Note:** You may need `sudo` privileges to run these commands. ### Target Gateways Installers Eclipse Kura™ provides pre-built installers for common development boards. Check the following [link](https://www.eclipse.org/kura/downloads.php) to download the desired installers. Take a look at [our documentation](https://eclipse-kura.github.io/kura/latest/getting-started/install-kura/) for further information on supported platforms and installer types. ### Docker Image Eclipse Kura™ is also available as a [Docker container](https://hub.docker.com/r/eclipsekura/kura/). Build ----- ### Prerequisites In order to be able to build Eclipse Kura™ on your development machine, you need to have the following programs installed in your system: * JDK 21 * Maven 3.9.9+
#### Installing Prerequisites in Mac OS To install Java 21, download the JDK tar archive from the [Adoptium Project Repository](https://adoptium.net/temurin/releases?version=21&os=any&arch=any). Once downloaded, copy the tar archive in `/Library/Java/JavaVirtualMachines/` and `cd` into it. Unpack the archive with the following command: ```bash sudo tar -xzf .tar.gz ``` The tar archive can be deleted afterwards. Depending on which terminal you are using, edit the profiles (`.zshrc`, `.profile`, `.bash_profile`) to contain: ```bash export JAVA_HOME=/Library/Java/JavaVirtualMachines//Contents/Home ``` Reload the terminal and run `java -version` to make sure it is installed correctly. Using [Brew](https://brew.sh/) you can easily install Maven from the command line: ```bash brew install maven@3.9 ``` Run `mvn -version` to ensure that Maven has been added to the PATH. If Maven cannot be found, try running `brew link maven@3.9 --force` or manually add it to your path with: ```bash export PATH="/usr/local/opt/maven@3.9/bin:$PATH" ```
#### Installing Prerequisites in Linux For Java ```bash sudo apt install openjdk-21-jdk ``` To install Maven you can follow the tutorial from the official [Maven](http://maven.apache.org/install.html) site. Remember that you need to install the 3.9.9 version.
### Build Eclipse Kura™ Change to the new directory and clone the Eclipse Kura™ repo: ```bash git clone -b develop https://github.com/eclipse-kura/kura.git ``` Move inside the newly created directory and build the target platform: ```bash mvn -f target-platform/pom.xml clean install ``` Build the core components: ```bash mvn -f kura/pom.xml clean install ``` Build the target profiles and the Eclipse Kura Target Definition: ```bash mvn -f kura/distrib/pom.xml clean install -DbuildAll ``` > [!TIP] You can skip tests by adding `-Dmaven.test.skip=true` in the commands above and you can compile a specific target by specifying the profile (e.g. `-Paarch64`). To list the available installer profiles, run: ```bash mvn -f kura/distrib/pom.xml help:all-profiles ``` Additionally you can build only the Eclipse Kura Target Definition, by running in the `distrib` folder: ```bash mvn -f kura/distrib/pom.xml clean install -Ptarget-definition ``` #### Build scripts Alternatively, you can use the build scripts available in the root directory. ```bash ./build-all.sh ``` IDE Setups ---------- We currently support two setups for Eclipse Kura™ development: - [**Eclipse Kura™ Development Environment Setup**](https://eclipse-kura.github.io/kura/latest/java-application-development/development-environment-setup/): This is the full setup allowing you to contribute to the core Eclipse Kura™ project codebase. It will install all the IDE plugins and formatters to have a pleasant development experience and clone the Eclipse Kura™ source code on your workstation. - [**Kura Addon Archetype**](https://eclipse-kura.github.io/kura/docs-develop/java-application-development/kura-addon-archetype/): The Kura Addon Archetype will allow you to develop applications or bundles running on Eclipse Kura™. It will install only the APIs and is best suited for developing Eclipse Kura™ add-ons. Contributing ------------ Contributing to Eclipse Kura™ is fun and easy! To start contributing you can follow our guide [here](CONTRIBUTING.md). ### Acknowledgments ![YourKit Logo](https://www.yourkit.com/images/yklogo.png) Thanks to YourKit for providing us an open source license of YourKit Java Profiler! YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications. YourKit is the creator of [YourKit Java Profiler](https://www.yourkit.com/java/profiler/), [YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/), and [YourKit YouMonitor](https://www.yourkit.com/youmonitor/). ================================================ FILE: SECURITY.md ================================================ # Security Policy This project implements the Eclipse Foundation Security Policy * https://www.eclipse.org/security ## Supported Versions The Eclipse Kura project provides security updates for the last two major releases. The fixes are applied to the latest minor release available for the given major and will produce a new service release. | Version | Last Release | Supported | | ------- | ------------ | ------------------ | | 5.6.x | 2025-12-09 | :white_check_mark: | | 5.5.x | 2024-07-08 | :x: | | 5.4.x | 2023-11-30 | :x: | | 5.3.x | 2023-07-07 | :x: | | 5.2.x | 2023-05-12 | :x: | | 5.1.x | 2022-06-30 | :x: | | 5.0.x | 2021-12-22 | :x: | | 4.1.x | 2021-12-22 | :white_check_mark: | | < 4.0.0 | 2018-10-19 | :x: | ## Reporting a Vulnerability If you think you have found a vulnerability in Eclipse Kura you can report it using one of the following ways: * [Report a Vulnerability](https://github.com/eclipse-kura/kura/security/advisories/new) * Contact the [Eclipse Foundation Security Team](mailto:security@eclipse-foundation.org) You can find more information about reporting and disclosure at the [Eclipse Foundation Security page](https://www.eclipse.org/security/). ================================================ FILE: build-all.sh ================================================ #!/usr/bin/env bash # # Copyright (c) 2016, 2026 Red Hat and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Red Hat # Eurotech # # activate batch mode by default MAVEN_PROPS="-B" # allow running tests [ -z "$RUN_TESTS" ] && MAVEN_PROPS="$MAVEN_PROPS -Dmaven.test.skip=true" mvn "$@" --color=always -f target-platform/pom.xml clean install $MAVEN_PROPS && mvn "$@" --color=always -f kura/pom.xml clean install $MAVEN_PROPS && mvn "$@" --color=always -f kura/distrib/pom.xml clean install $MAVEN_PROPS ================================================ FILE: checkstyle_checks.xml ================================================ ================================================ FILE: kura/distrib/.gitignore ================================================ build.properties !bin RELEASE_INFO ================================================ FILE: kura/distrib/RELEASE_NOTES.txt ================================================ Eclipse Kura - 4.1.1 - May 2020 ------------------------------------------------------------------------- Description: Eclipse Kura 4.1.1 is a service release to address various discovered bugs and functional issues. Changes: * Enhancements * Enhanced the modem support with Huawei MS2372, Zte ME3630, SimTech SIM7000 LTE NB-IOT, Quectel EG25 * Target Platform Updates * Jetty 9.4.19.v20190610 * H2DB 1.4.199 * Paho 1.2.1.k2 * Bug fixes and cleanups * Fixed modem reset issue when the value is configured to 0 (no reset) * Fixed issue with multiple cloud connections * Fixed issue with parsing of ip route command * Fixed issue where assets with only write channels still can call driver.read() method * Fixed issue with token bucket where a change of system type can inpact with the token bucket functionality * Fixed issue where a change in system tyme could impact the Wires Timer * Fixed issue with Asset channel restore functionality * Fixed issue with DEPLOY-V2 failure message publishing * Fixed issue with Paho overriding SSL settings * Fixed issue in CanConnection service with multiple can interfaces * Fixed issue with modem switching from data mode to command mode * Fixed issues with modem reset Compatibility: * Eclipse Kura v4.1.1 does not introduce API breakage with previous releases. * Kura 4.1.1 introduces H2DB v.1.4.199 that requires to delete/upgrade the existing persisted database to be compatible with this new version. Please refer to http://www.h2database.com/html/tutorial.html#upgrade_backup_restore Target Environments: * Kura is released as pre-compiled binary installers for the following platforms: * Raspberry Pi 2/3 based on Raspbian * Intel Up Squared board running Ubuntu 18 * Intel Up Squared board running Centos 7 (Experimental) * Rock960 ARM_64 running Ubuntu 16 (NN version only) * Kura is also available as a pre-built Docker container Bug Fixes : * Fixed github issues: * #2831: ModemMonitorServiceImpl should use monotonic clock * #2828: Improve modem help section * #2827: Entering wrong dial string and APN can cause a reset loop * #2825: Kura 4.1.x SupportedUsbModems isAttached method can fail * #2822: CommConnectionImpl constructor does not close the serial port on failure * #2820: Modem reset can lead to SIM card not ready * #2811: CanConnection service with multiple can interfaces * #2809: Unescaped loop on modem reset failure * #2800: Switching from data mode to command mode does not work in pppd chat script * #2793: Paho 1.2.1 overrides Kura SSL configuration * #2759: [DEPLOY-V2] Failure status reported by a verifier script is not published * #2679: One of two CloudConnections sometimes fails to connect and never tries to reconnect * #2639: Asset configuration reseted after uploading new channels * #2626: Asset with only write channels still calls driver.read() method * #2605: Wires Timer stop ticking if system time is set in the past * #2581: [DataService] Use System.nanoTime for token bucket * #2580: Setting modem reset timeout to 0 causes the modem to reset indefinitely * #2540: Default gateway is not correctly parsed * #2437: Add support for Huawei modem MS2372 * Merged no issue-related Pull Requests: * #2805: Added policies to iptables * #2804: Fixed DB bundle reference in dev-env. * #2665: Added support for Quectel EG25 * #2622: Support for SimTech SIM7000 LTE NB-IOT modem * #2611: Zte ME3630 LTE modem support * #2558: udhcpc pid file parameter fix * #2511: Updating jetty to 9.4.19.v20190610 * #2484: Fixed H2db invocation in config.ini file. * #2466: Updated H2DB to version 1.4.199 * #2404: HostapdManager: use absolute path to pid file instead of relative Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection will encounter a failure. * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * #2414: Rock 960: cannot get client id * #2038: [Kura 3.2.0 QA] Package uninstallation log * #2013: Unsaved changes dialog triggers incorrectly * #1993: Search Domains Are Not Supported * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English * #1663: Authentication Issue with Deploy V2 * #1572: serial modbus has errors on some hardware * #1533: MqttDataTransport client-id illegal character * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0 * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1016: ConfigurationServiceImpl creates duplicate instances * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #654: Clean up static initialization around "modem" functionality * #645: Clean up internal dependencies in Kura * #522: [Net] Modem monitor should monitor interfaces, not modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #348: WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set * #329: [DEPLOY-V2] Review/refactoring needed * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation Eclipse Kura - 4.1.0 ------------------------------------------------------------------------- Description: Eclipse Kura 4.1.0 is a minor release dedicated to introduce several new features and continue the process of overall usability improvement. The development team spent also a lot of effort trying to refactor and improve the overall code quality. New and Noteworthy: * APIs * New APIs for KuraBirthPayload, KuraDeviceProfile, KuraDisconnectPayload * Features and Enhancements * Enhanced the JSON Service with JSON Message marshalling/unmarshalling * Added timestamp to Lifecycle Messages * Target Platform Updates * Google Guava 25.0-jre * Eclipse Milo 0.2.4 * Apache Fileupload 1.3.3 * Apache Artemis 2.6.4 * Eclipse Paho 1.2.1 * Bug fixes and cleanups * Fixed unnecessary escaping in Drivers and Assets UI * Fixed issue where asset failure messages were not displayed * Fixed a bug where the user could not set cellular attempts option to 0 * Fixed incompatibility with systems without iwlist * Solved a possible OSGi framework refresh when a dp is uninstalled or reinstalled * DEPLOY-V2 cloudlet fixes for GET calls Deprecated APIs: * Deprecated old Bluetooth APIs not based on tinyB Compatibility: * Eclipse Kura v4.1.0 does not introduce API breakage with previous releases. * The Command Service is now disabled by default. To use it, the user needs to opt-in to this feature, enabling the service from configuration. Target Environments: * Kura is released as pre-compiled binary installers for the following platforms: * Raspberry Pi 2/3 based on Raspbian * Intel Up Squared board running Ubuntu 16 * Intel Up Squared board running Centos 7 (Experimental) * Rock960 ARM_64 running Ubuntu 16 (NN version only) * Kura is also available as a pre-built Docker container Security Fixes: * CVE-2016-1000031 * CVE-2018-10237 * CVE-2019-10242 * CVE-2019-10243 * CVE-2019-10244 Bug Fixes : * Fixed github issues: * #2423: [Kura QA 4.1.0] Emulator in Oomph installer * #2421: Artemis Server manager NullPointer exception * #2418: Kura does not support systems without iwlist * #2417: [Kura 4.1.0 QA] Asset configuration radio buttons * #2412: Paho issue with WS broker * #2407: Can't set cellular connection attempts to 0 * #2399: Update Paho to latest version available * #2389: Unnecessary escaping in Drivers and Assets data UI * #2388: Update Artemis to 2.6.4 * #2382: Asset operation failure messages are not always shown * #2372: Add Timestamp to Lifecycle Messages * #2353: [ConfigurationService] Loading unencrypted snapshots discards line breaks * #2352: Guava CVE-2018-10237 * #2334: The old Bluetooth APIs should be deprecated * #2330: BLE Beacon data assembly overflow * #2324: Possible OSGi framework refresh when a dp is reinstalled * #2313: Typos in ExamplePublisher metric name and descriptions * #2301: kura.data.dir unused * #2300: Drivers and Assets description is appended * #2296: The BluetoothLE example fails when the cloudPublisher is undefined * #2290: [Kura 4.0.0 QA] Shutdown issue when started multiple times * #2256: Deploy-V2 cloudlet GET status stops responding * #2069: Marketplace install when LAN-only * #362: Uninstaller leaves most of the files * Merged no issue-related Pull Requests: * #2432: Fix GPS enable when PPP is not configured * #2429: Fixed NPE on DhcpClientLeaseBlock * #2416: Fixed issues for Kura on Intel UP2 Ubuntu * #2395: Removed wrong if section in emulator position. * #2394: Fixed lint issues * #2387: CentOS/RPM uninstallation cleanup * #2386: OPCUA Driver updates * #2385: Solved some new lint issues. * #2380: Fixed lint issues * #2379: Moved KuraBirthPayload, KuraDeviceProfile and KuraDisconnectPayload to APIs * #2377: Added missing byte array conversion in optimiser library * #2376: Changes to expose simple message creation in corresponding JSON service * #2373: Added support for null notification publisher in deploy-v2. * #2370: Cleanup Kura folders * #2368: Implemented fixes for possible XXE attacks to XML parsers. * #2366: Changed joint shapes file to default and applied corresponding changes in wires_composer.js file. * #2362: Fixed regression when saving empty wire graph * #2358: Fixed few more lint issues. * #2357: Fixed notification publisher topic. * #2355: Fixed regression in CloudService tab ordering * #2349: Added check for resolv.conf symlink * #2348: Improved Web UI configuration loading * #2347: Solved some blocking lint issues * #2346: Changes to solve lint issues in CloudConnectionStatus. * #2345: Fixed lint issue * #2344: Solved some major lint issues in MqttDataTransport.java * #2343: Removed stale cmpn references. * #2342: Refactored console code in web2 bundle. * #2333: Another tentative fix to solve lint issue in file check * #2331: Removed osgi.cmpn api bundle. * #2329: Updated retrieving of system parameters on Windows * #2328: Solved some more lint issues * #2327: Changes to fix possible path injection attack in skinServlet. * #2325: Few lint issues fixes * #2309: Always use double as GainOffset return type * #2305: Remove the Jetty version from Server reply. * #2306: Removed unnecessary jaxb imports * #2302: Provide class to LogManager.getLogger() Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection will encounter a failure. * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * #2414: Rock 960: cannot get client id * #2038: [Kura 3.2.0 QA] Package uninstallation log * #2013: Unsaved changes dialog triggers incorrectly * #1993: Search Domains Are Not Supported * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English * #1663: Authentication Issue with Deploy V2 * #1572: serial modbus has errors on some hardware * #1533: MqttDataTransport client-id illegal character * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0 * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1016: ConfigurationServiceImpl creates duplicate instances * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #654: Clean up static initialization around "modem" functionality * #645: Clean up internal dependencies in Kura * #522: [Net] Modem monitor should monitor interfaces, not modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #348: WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set * #329: [DEPLOY-V2] Review/refactoring needed * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation Eclipse Kura - 4.0.0 ------------------------------------------------------------------------- Description: Eclipse Kura 4.0.0, compatible with Java 9 and OSGi R6, introduces a new model that simplifies plugging new cloud connection implementations. It brings up a restructuring of the networking part to make it more pluggable and expandable, new drivers and supported platforms, as well as improvements to usability and bug fixes. Being a major release, it also includes breaking changes and removes support for code and platforms no longer maintained by the original contributors. New and Noteworthy: * APIs * Cloud Connections: New Cloud Connections APIs that simplify the integration of third party cloud providers, simplifying the development of user applications * Alerts: New Alerting model for special type of messages generated from the device * New Bluetooth LE APIs to leverage new TinyB features: updated the TinyB library and updated Kura APIs to leverage the new changes provided by the referenced library  * Features * Eclipse IoT WG Cloud Connection: A new Cloud Connection provider that leverages the new Cloud Connections APIs and enables Kura to connect with remote providers that support the new Eclipse IoT WG Namespace. E.g. this provider supports the integration with Eclipse Hono through the MQTT Adapter * Kura Docker container: New Docker Container that wraps in a Centos 7 environment a Kura No Network installation. * Upload of Asset channels from CSV file: In the Asset view, the user can now download and upload channel descriptions as CSV files. * Enhancements * Non-blocking assets configuration updates * Wires Graph Blinking rate limit * Added fix validity, latitude and longitude hemisphere fields to GPS NMEA Position * Reduced CPU usage by Kura Wires * Refactor and Cleanup * Modular support of new platforms: Refactoring of framework structure to support, in a pluggable way, different operating systems and service managers (SysV, Systemd) * SSL Manager Service: Service refactoring and cleanup. By default, Kura uses for secure communications its own cacerts.ks keystore instead of the one provided by the Java VM. The default installation provides a cacerts.ks keystore that contains only the Eclipse leaf certificate. To connect to a different provider or broker, the user must install the corresponding certificate in the cacerts.ks keystore, for example using the Kura web UI. * New framework folder structure: The framework folder structure has been redesigned to simplify the user interaction. * Drivers * New drivers available also in the Eclipse Kura Marketplace: * iBeacon Scanner * Eddystone Scanner * Dummy Driver * New Hardware Platforms and Distributions * Intel UP Square Boards running Ubuntu and CentOS * Rockchip Rock960 AARCH 64 running Ubuntu * Target Platform Updates * Eclipse Equinox 3.12.50 (Oxygen) * Eclipse Milo 0.2.1 * Apache Log4j2 2.8.2 * SLF4J 1.7.25 * Apache Artemis 2.5.0 * Apache Camel 2.21.1 * Intel Tinyb 0.5.1 * Eclipse Paho 1.2.0 * GWT 1.8.2 * Breaking Changes: * Removed APIs and implementation supporting HSQLDB * org.eclipse.kura.net package cleanup and removal of deprecated APIs * Removed deprecated newWireSupport as causing invocation loop * Removed SslManagerServiceOptions class and modified SSLManagerService APIs * Modified "verifySignature" method in Certificates APIs to accept, as first argument, KuraApplicationTopic instead of KuraTopic * Removed WireService API and references * Deprecated APIs * KuraTopic * CloudCallService * CloudClient * CloudClientListener * Cloudlet * CloudletTopic * CloudService * CloudServiceFactory   * Discontinued Hardware Platforms and Distributions: * Intel Edison * TI BeagleBone Black * PC Engines APU * Fedora distribution for the Raspberry Pi * Raspberry Pi B+ * AARCH64 * Unmaintained Code * Karaf Compatibility: * Eclipse Kura v4.0.0 introduces API breakage with previous releases. * Containing a folder restructuring, a cleanup of the destination filesystem is required before installing the new version of Kura * The Command Service is now disabled by default. To use it, the user needs to opt-in to this feature, enabling the service from configuration. Target Environments: * Kura is released as pre-compiled binary installers for the following platforms: * Raspberry Pi 2/3 based on Raspbian * Intel Up Squared board running Ubuntu 16 * Intel Up Squared board running Centos 7 (Experimental) * Rock960 ARM_64 running Ubuntu 16 (NN version only) * Kura is also available as a pre-built Docker container Bug Fixes : * Fixed github issues: * #2279: [Kura 4.0.0 QA] Service disappears from menu when reconfigured * #2278: Firewall, "Open port" dialog validation * #2272: Asset CSV upload/download issues if AD name and id differs * #2271: [Kura 4.0.0 QA] Adding wires components in IE/Edge * #2264: [Cellular] PDP Auth failed using context #1 in 4G network (Telit LE910-EU1 and LE910-V2 EU, possibly NA versions) * #2263: Cloud connections table refresh * #2262: Cloud connection PID validation * #2243: [Security] Possible XML External Entity (XXE) attack * #2239: WireAsset Configuration UI check box status can not be saved * #2233: Create CloudServiceFromFactory and Delete CloudServiceFromFactory cause null reference * #2232: Linker issue with tinyb * #2224: Wire Publisher can't initialize properly at kura start * #2219: Update Jetty to version 9.4.12 * #2215: NPE during package installation via cloud * #2213: Update TinyB and Bluetooth API * #2210: Remove HSQL db support from code and implementation * #2205: [OPC-UA Driver] Authentication not working * #2202: [DhcpClientLeaseBlock] Failed to add a lease block due to an error parsing dhclient lease file * #2199: BLE iBeacon scanner configuration not synched with code * #2196: BLE provider logging failure * #2189: HTTPS redirects to HTTP * #2185: [Test] Cleanup tycho-surefire-plugin configurations a bit * #2184: [ConfigurationService] XML Marshaling Providers need to be started before * #2181: H2DB file fragmentation * #2169: H2DB file corruption * #2164: [Asset] Make configuration updates non-blocking * #2163: [Paho] WSS connection break silently after a few hours * #2162: [Wires] Implement rate limit in servlet for wires blinking * #2158: [GPS] Add missing fields in NMEA Position * #2153: [DEPLOY-V2] intallVerificationDir is never initialized * #2149: Cloud zip file upload * #2145: Remove libmatthew-java * #2143: Camel XML router service missing * #2138: Cloud service selection in examples * #2125: Impossible to upload device key pair * #2120: BeaconScanner example publishes with qos 2 * #2117: Remove Windows bundles * #2115: Artemis 2.5.0 and dev-env * #2114: Review supported platforms * #2110: Add Dummy Driver * #2108: Create a new Cloud Stack for the new D2C Messaging * #2107: Integrate Device to Cloud (D2C) Interaction Type * #2102: emitAllReadChannels method doesn't handle Runtime exceptions * #2101: [Web UI | Driver and Assets]: Show the Asset Read Error Message * #2096: [NetAdmin] Issues using GPS if modem has never been enabled * #2091: version `GLIBCXX_3.4.20' not found * #2089: [NetAdmin] Some state of the logic that manages modems persists across resets * #2087: [NetAdmin] Race condition between NetAdmin and PositionService after modem reset * #2085: [NetAdmin] Fix AT escape sequence timings in TelitModem * #2079: Empty channel descriptor * #2078: Native Support for UP Development Kit * #2072: Weird behaviour on webUI when click on CloudServices * #2070: Icon not working for factory components * #2068: The duration of Beacon scan should be in seconds * #2067: DataService enable.recovery.on.connection.failure is causing a reboot systematic on first boot * #2065: [Web2] AlertDialog causes duplicate ids * #2057: Upgrade Camel version to 2.21.1 * #2055: DefaultCloudServiceFactory manages all CloudServiceImpl instances * #2050: Modem monitor in Not connected state does not trigger reset * #2045: Add support for CloudConnectionStatus with inverted gpio LED * #2040: [Kura 3.2.0 QA] PositionService does not switch between GPS and static position * #2037: The interface number for usb tty devices should be retrieved by the native library * #1999: Connection refresh sometimes causes duplicate entries * #1957: [Wires] Allow using the component name as label * #1933: Support SCR/Declarative Services 1.3+ * #1921: Consider using EquinoxLauncher instead of the EclipseStarter * #1911: [Artemis] Upgrade to version 2.5.0 * #1849: SSL Configuration - Keystore path change doesn't work * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position * #1255: Switch away from log4j 1.x * #1186: Get ready for Java 9 * #689: Upgrade to Camel 2.18.x * #673: CloudServiceFactory deleteConfiguration * #651: Call to "exit()" in native code * #520: [Net] PppFactory is not a factory and its design is wrong * #518: [Net] Modem monitor concurrency issue with multiple modems * #208: Include camel-amqp component jar in base distribution * #181: [GPS] position service: code review * Merged no issue-related Pull Requests: * #2288: Changes to prevent usage of the same db table between different cloud connections * #2285: Changes to the binary parser library * #2276: Changed validity checks for RMC strings * #2273: Fixed dev-env launch configs. * #2270: Updated Eclipse SSL cert to enable connection to Eclipse Mqtt broker. * #2269: Set the command service as disabled per default. * #2266: Disabled apparmor at framework installation. * #2260: Fixed modem monitor * #2259: Fix wrong reference to certificate servlet. * #2257: Update to equinox wireadmin 1.0.800 * #2255: Added the interfaceName as argument in monitor listeners; fixed NPE * #2251: Fixed old wireService reference. * #2231: Avoid saving snapshot at shutdown * #2230: Fixed cloud connection status url linux path parsing * #2229: Add another type converter for Wires/Camel integration * #2228: Fix a typo in the log message * #2221: Fixed notification publisher topic. * #2222: Fixed change in asset configuration property types * #2216: Implemented forcing endpoint URL in OPCUA driver * #2212: Improved subscription management in default CloudEndpoint * #2198: Synchronized BLE iBeacon scanner configuration with code * #2194: Updated configuration label in BLE example * #2192: Stop default H2 db service * #2191: Set payload timestamp in BLE scanner examples * #2188: Use log4j2 in emulator and tests * #2175: NMEAParser class cleanup * #2173: Implemented nonblocking config update for s7 driver * #2126: Updated wires devel components to use new API * #2112: Fix the creating of a random topic * #2099: Save two process forks when writing the config files * #2094: Sort interfaces alphabetically * #2083: Improve debug output of known wires * #2081: Fix Wire component labels * #2071: Simplify ifcfg config * #2063: Fix a NPE and provide proper cause of error * #2061: Fixed lint issues * #2053: Update to Eclipse Milo 0.2.1 * #2041: Started fixing archetype * #1978: Modbus TCP incorrectly reads frame length * #1940: Solved some possible NPEs in web2 bundle. * #820: Upgrade to GWT 2.8.2 Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE also tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection will encounter a failure. * WiFi on Raspberry Pi 2 has only been tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * #2069: Marketplace install when LAN-only * #2038: [Kura 3.2.0 QA] Package uninstallation log * #2013: Unsaved changes dialog triggers incorrectly * #1993: Search Domains Are Not Supported * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English * #1663: Authentication Issue with Deploy V2 * #1572: serial modbus has errors on some hardware * #1533: MqttDataTransport client-id illegal character * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0 * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1016: ConfigurationServiceImpl creates duplicate instances * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #654: Clean up static initialization around "modem" functionality * #645: Clean up internal dependencies in Kura * #522: [Net] Modem monitor should monitor interfaces, not modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #362: Uninstaller leaves most of the files * #348: WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set * #329: [DEPLOY-V2] Review/refactoring needed * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation Eclipse Kura - 3.2.0 ------------------------------------------------------------------------- Added Features : * Multiport Wires Components: Add Wires components with multiple input/output ports to allow for better routing of data through the Wire Graph. With the addition of new arithmetic and conditional Components, this will allow more flexibility and usability in creating logical flows through the Graph. * Wires Conditional Component: Add Wires component that facilitates if/then/else logic. * Wire Arithmetic Component: Add Wires component that facilitates basic arithmetic functions. This bundle is available as an example project. * Wires Statistical Component: Add Wires component that performs basic statistical analysis. This bundle is available as an example project. * Wires Join Component: Add Wires component that performs join operations. * Wire Publisher Position: Add support for device position in published messages. The user can decide whether or not having the position included in messages published to the cloud and also the verbosity of the position information included. * Wire Graph export: Add support, in the wire composer, to export only a working wire graph. * Assets: Add support for event driven Drivers * Assets: Channels can now be individually enabled and disabled. * Drivers: To further extend the usability of Kura, new Drivers for GPIO, Raspberry Pi SenseHAT, and Event Driven Drivers will be introduced. Compatibility: * Eclipse Kura v3.2.0 does not introduce API breakage with previous releases. Target Environments: * Kura is released as pre-compiled binary installers for the following platforms: * Raspberry Pi based on Raspbian: Raspberry Pi, Raspberry Pi B+, Raspberry Pi 2/3 * BeagleBone Black based on Debian * Fedora on ARM (Experimental) * Intel Edison (Experimental) * APU Debian (Experimental) * ARM_64 Debian (Experimental) Bug Fixes : * Fixed github issues: * #2042: Switching network interface status from 'L2Only' to 'Unmanaged' doesn't work. * #2022: Factories don't get removed from creation dialog * #2020: Wrong column content in assert/driver view * #2015: New Factory Component - drop-down-list item missing for a installed package * #2014: Deleting a component keeps tab open * #2012: DB-H2-012 fails * #2010: Exception when disabling watchdog * #2009: DATA-LIMIT-001 fails * #2007: Array validation doesn't work properly * #2002: DEN-DEPLOY-005 failed * #1997: Improve dhcpd shutdown logic * #1853: SensorTagDriver sometimes fails to connect to the SensorTag * #1975: [Kura 3.2.0 QA] Warning logged uploading and old Asset snapshot * #1973: [Kura 3.2.0 QA] Wire graph snapshot includes the Meta Type OCD * #1971: EthernetMonitor can't monitor more than two ethernet interfaces * #1970: [Kura 3.2.0 QA] Multiple handling of PositionLocked * #1959: [Web] Escaping doesn't seem to work properly * #1956: [Wires] Creating a component named ")" is possible * #1955: [Wires] New Wire Component name entry field is broken * #1941: [DbDataStore] Stale messages not purged with timezone other than UTC * #1936: [Driver] Improve the way Driver instances are shared between consumers * #1928: Removing and reinstalling the Script Filter dp causes a lot of components to be restarted * #1924: [Wires] Script Filter and Conditional use different syntax * #1914: User should be able to set PDP context number for setting APN. * #1907: [WireAsset] Implement Driver generated single timestamp * #1906: [Wires] Download graph as a (partial) configuration snapshot * #1905: [WirePublisher] Add option to publish the geographic position * #1902: Allow to enable/disable channels in asset configuration * #1894: Show Wire Component description in the Web Ui * #1892: Add SenseHat Driver * #1886: Package unistall error * #1878: Add support for "Unmanaged" mode for network interfaces. * #1876: Packages URL downloader does not use Kura's SSLContext * #1874: Change the reboot cause string * #1870: Develop a GPIO Driver for Kura Wires * #1863: IBeacon decoder index out of bounds * #1861: Implement a WireAsset reacting to channel changes * #1859: [Drivers and Assets] The channels names and labels in dropdown lists aren't sorted * #1856: DEPLOY-V2: download always uses the defalut java keystore * #1843: BaseChannelDescriptor contains some inconsistencies * #1840: [OPC-UA] Improve type conversions in OPC-UA driver * #1836: Jetty security issue * #1835: [Documentation] AWS connection needs TLSv1.2 * #1834: [OPC-UA] The OPC-UA driver should not specify timestamps on write requests * #1826: LE910 V1 doesn't turn back on at modem reset. * #1823: Failure to submit Wifi configuration when wifi password (PSK) ends with the $. * #1822: [Wires] Faulty refresh in Chrome * #1821: [Wires] New Wires features don't work in IE * #1816: [Emulator] NumberFormatException while installing new packages * #1815: [Wires] Channel timestamp should be optional * #1813: Marketplace dp installation popup drop-zone * #1812: [PortFwd] Fields for internal and external ports mixed up * #1811: Wires: Multi-port components and graph execution model * #1809: [Wires] Drag and drop should respect canvas grid * #1808: Define the JSON WireService persistence form * #1807: [Wires] Add Component Multi Port support * #1802: [Wires Refactoring] Wires WebUi refactoring * #1801: Refactor Wires js code. GWT client should be the orchestrator. * #1800: Modify Client code so GWT client prepares wire component configuration from GwtWireGraphConfiguration * #1799: Modify code so GWT client calls jointjs to build graph from GwtWireGraph * #1798: Move Wires-related code out of the GWT Server part * #1797: [Wires Refactoring] Implement new Wires APIs * #1796: [Wires Refactoring] Review APIs * #1795: Refactor WireServiceImpl to also implement WireGraphService * #1793: Update ConfigurationService API with new methods to handle factory OCDs * #1792: Define WireGraphService and deprecate WireService * #1786: Wire publisher do not include a timestamp in the message * #1778: [Wires] Web Ui error when deleting a not saved component * #1777: [Wires] Drag and drop glitch * #1776: [Wires] Add a refresh button in Wire Composer * #1773: Kura DB Store Query * #1772: Remove the icons from the "new component" dialog * #1770: CloudService instance hint should be persistent while the user writes * #1761: NetworkAdminServiceImpl: submitFirewallConfiguration blocks for 30 seconds * #1758: [Web UI] Initial page view on a narrow screen * #1757: Remove GpsClockSyncProvider in Clock Service * #1753: Typo in Eddystone provider component definition * #1737: CloudClient subscribes to more topics than requested * #1734: Display of asset channel data in WebUI in case of failures * #1703: [Kura 3.1.0 QA] Wires page jumping up and down * #1700: [Kura 3.1.0 QA] Rollback doesn't restore deleted services * #1689: Instaling a dp can cause the WebUI to restart * #1657: Bluetooth notifications do not work * #1632: Cleanup old scripts in distrib/resources folder * #1268: [WebUI] Usability Improvements * #1213: [Wires] Should DB Filter clean the cache on empty result set? * #1193: [Wires] Component avoidance during initial placement * #1188: [Wires] Components can be hidden outside the graph area * #1092: Possible NPE and non-working check * #890: [Kura 2.1.0 QA] Snapshot management in web UI * #590: [Cloud] CloudConfigurationHandler casts to ComponentConfigurationImpl without type check * #520: [Net] PppFactory is not a factory and its design is wrong * Merged no issue-related Pull Requests: * #2044: Fixed dhclient issue after Raspbian fresh install * #2039: Fixed rotation issue in sensehat driver * #2036: Fix for modem serial ports detection and ppp * #2035: Fixed possible NPE in sensehat driver * #2034: Added stop watchdogd step to WatchdogService * #2028: Removed localisation from o.e.k.w.provider bundle * #2023: Removed 'Search Domains' field * #2016: Modified wrong reference to internal modem * #1996: Added dp for gpio driver * #1992: Re-enable plain Fedora installer in addition to RPMs * #1988: Backport maintenance fixes * #1985: DIO: fix unsafe casts in native code for 64 bits architectures * #1984: Changed gpio bundle defaults, removing the hardcoded gpio 1. * #1974: Fixed wrong pid reference in configuration upgrade class. * #1968: Fixed too strict package imports * #1966: Added missing since in APIs for modem management. * #1963: Prevent getters from creating new object instances * #1954: Fixed possible NPE in OPCUA driver * #1949: Added notifications on SensorTagDriver and fix several bugs in SensorTagExample * #1947: Fixed modem reset functionality. * #1944: Fix a possible NPE * #1943: o.e.k.w.c.provider: fix Import-Package version range * #1931: WireAsset: do not log errors if they are emitted * #1925: Changed exists plugin default. Now it's disabled. * #1917: Improve the description of a few settings * #1915: [H2] Updated service description * #1913: Wires composer robustness and usability improvements * #1891: Fixed potential malfunction of Eddystone-UID advertiser with some hcitool versions * #1888: Added tcp socket connection timeout * #1848: Disabled the kura.primary.network.interface property. * #1847: HTML IDs * #1829: URL.openStream() creates a new connection without SslContextFactory set * #1755: Modified the success notification in order to not being executed in a different thread. * #1738: Modified localization.resources fragment to reference the host with a version range. * #1432: Remove Intel Edison Profile Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection will encounter a failure. * The TinyB library used by the Bluetooth LE API implementation sometimes cause a JVM crash. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #2050: Modem monitor in Not connected state does not trigger reset * #2040: [Kura 3.2.0 QA] PositionService does not switch between GPS and static position * #2013: Unsaved changes dialog triggers incorrectly * #1999: Connection refresh sometimes causes duplicate entries * #1995: Failed NET-WIFI-003 on Fedora * #1993: NET-ETH0-003 failed * #1932: SystemAdminService.getUptime() returns SystemAdminService#UNKNOWN on MacOS when locale is not English * #1788: Maven Archetype does not work - or can someone show me how to use it? * #1663: Authentication Issue with Deploy V2 * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted * #1572: serial modbus has errors on some hardware * #1533: MqttDataTransport client-id illegal character * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0 * #1414: SCR exception running Kura Wires in Karaf * #1373: [Kura 3.0.0 QA] Configuration service: mixing configurable services with factory components * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1016: ConfigurationServiceImpl creates duplicate instances * #924: [Kura 2.1.0 QA enh] Non-trimmed values of configuration parameters * #923: [Kura 2.1.0 QA] eth0 search domain configuration and storage * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #654: Clean up static initialization around "modem" functionality * #651: Call to "exit()" in native code * #650: Possible bug in "LinuxUdev.c" * #645: Clean up internal dependencies in Kura * #522: [Net] Modem monitor should monitor interfaces, not modems * #520: [Net] PppFactory is not a factory and its design is wrong * #518: [Net] Modem monitor concurrency issue with multiple modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #362: Uninstaller leaves most of the files * #348: WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set * #329: [DEPLOY-V2] Review/refactoring needed * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation Eclipse Kura - 3.1.0 ------------------------------------------------------------------------- Added Features : * H2 Databases: This release will see the switch from HSQLDB to H2. This migration will allow for a number of performance improvements as well the ability to maintain multiple database instances. * REST API for Kura Drivers and Assets: To allow more flexibility, REST endpoints will be added to Kura for interacting with the Kura Drivers and Assets instances. * Embedded Artemis Broker: The addition of the Apache Artemis Broker will extend Kura's messaging functionality. * BLE via TinyB: To improve the reliability of BLE, Kura will switch to the TinyB library to support BLE via Bluez. * Kura Wires Functional Logic: To extend the usability of Kura Wires, this release will include Functional Logic Wire Components. This will allow the use of plain JavaScript inside a Wire component. * Kura Web UI Update: A new UI element will be added for managing and editing Drivers and Assets. * S7 Industrial Protocol: A new driver will be added to the Eclipse Marketplace to support S7. * BLE/SensorTag: A new driver will be added to the Eclipse Marketplace to support BLE on the TI SensorTag. * MQTT publish rate improvement: A limit parameter will be added to the MQTT transport service to allow throttling of MQTT messages to prevent unnecessary congestion on the MQTT broker. * Connection Monitor: A connection monitor will be introduced to the DataService to further improve connectivity reliability. * RPMs: This release will provide RPM packaging for Fedora based distributions. Compatibility: * Eclipse Kura v3.1.0 does not introduce API breakage with previous releases. * This release does introduce a new set of APIs for TinyB for interacting with BLE devices. Support for previous BLE APIs will still be present and functional. * In Kura v3.1.0 it is possible to instantiate a Driver instance from the Drivers and Assets section or from Wire Composer only if the following requirements are met: - the Driver implementation class must implement the following interfaces: - Driver - ConfigurableComponent or SelfConfigurableComponent - the Driver must provide a component definition xml file that advertises that the interfaces mentioned above are provided and that sets "required" as configuration policy. It is advisable to update the deployment packages of non compliant drivers if needed. It is still possible to instantiate non compliant drivers using the "+" button under "Services". Target Environments: * Kura is released as pre-compiled binary installers for the following platforms: * Raspberry Pi based on Raspbian: Raspberry Pi, Raspberry Pi B+, Raspberry Pi 2/3 * BeagleBone Black based on Debian * Fedora on ARM (Experimental) * Intel Edison (Experimental) * APU Debian (Experimental) * ARM_64 Debian (Experimental) Bug Fixes : * Fixed github issues: * #1725: [Kura 3.1.0 QA] Cloud Services GUI crashes * #1724: [Kura 3.1.0 QA] WiFi DHCP: Gateway IP wrong in GUI * #1720: [Kura 3.1.0 QA] SensorTagDriver NPE if wrong address * #1707: [Kura 3.1.0 QA] BLE iBeacon* only react to company code 004c * #1702: [Kura 3.1.0 QA] Artemis in emulator * #1685: [WebUi] Security policy fingerprint UI does not expand * #1680: getKuraMarketplaceCompatibilityVersion() always returns kura.version * #1665: Create rpm installer for Fedora * #1661: The driver configuration is not applied * #1645: Development environment needs to be updated * #1641: Oomph installer needs to be updated * #1630: Wifi password check failing * #1590: [Assets and Drivers] Byte arrays are not displayed properly * #1588: Password arrays are not well managed by ConfigurationService * #1585: [Messaging] Share cloud connection with external applications * #1575: [Watchdog Service] Write the last reboot cause to a persistent file * #1564: [MqttDataTransport] wss connections without hostname verification do not work * #1558: CommandCloudApp doesn't use received working directory parameter * #1556: connect.retry-interval=0 causes DataService activation failure * #1541: Add support for polling to GPIO example * #1531: Create "Drivers and Assets" tab * #1530: Modify the wire composer to allow driver management * #1517: Verify compatibility of the old Bluetooth implementation with Bluez 5.43 * #1513: H2 DB: Web app and TCP server are mutually exclusive * #1511: Add Artemis broker to Kura core * #1506: H2 DB: Changing the db user does not work * #1502: H2 DB: Default service can be deleted * #1501: H2 DB: invalid service configuration not indicated * #1471: [Wires] Deleting a Timer instance might stop all other Timers * #1462: Wire Components list has no scrollbar * #1455: Wiki page documenting H2 use cases * #1453: Remove unused lib directory from org.eclipse.kura.linux.usb * #1447: New BLE beacon/advertisement API * #1442: Add TinyB host and fragment bundles in target-platform * #1435: Snapshot problem on wires * #1429: Support arm 64 bits platform * #1421: Replace HSQLDB with H2 * #1420: Promote Assets and Drivers like Cloud Services in the Web UI * #1417: Implement DataService connection monitor as a CriticalComponent * #1416: Limit the rate of messages published by the DataService * #1413: Implementation of a SensorTag Kura Driver * #1412: Beacon/advertisement implementation of the new BLE API * #1411: GATT Implementation of the new Bluetooth Low Energy API * #1409: New Bluetooth Low Energy API * #1405: Fix trivial Sonar Lint problems in the network bundles * #1396: [Beaglebone Black] Log4j log level set to DEBUG * #1391: [Wires] Fifo is really FIFO only while it's full * #1386: [Wires] Null properties in channel configuration are not properly handled * #1384: OPC UA Driver channel descriptor property ids shouldn't be localised * #1383: OPC UA Driver only supports string node ids * #1378: [Wires] DB store primary key * #1376: [Wires] Asset configuration is not updated after a ChannelDescriptor change. * #1369: WiFi password (PSK) can't contain '&' * #1363: [Documentation] Add tutorial on Eclipse Kapua connection * #1362: [Documentation] Kura documentation improvements * #1361: [Documentation] Improve Kura wires documentation * #1360: [Documentation] Add Administration section in Kura documentation * #1359: [Documentation] Add Configuration section in Kura documentation * #1354: Document default tracking of services registering Configurable/SelfConfiguringComponent * #1338: [Kura 3.0.0] camel.aggregation and camel.quickstart examples should be "normalized" * #1325: [Wires] Exception if an Channel Descriptor contains in Option of Integer type * #1321: 64bit Linux version broken * #1288: Clean up JavaDoc of KuraPayload * #1250: Drag and drop of Marketplace listing should send back a successful install count * #1243: Distribute publishing over time * #1207: [Driver] Contribute Siemens S7 Driver * #1196: [Net] PPP password is not a (MetaType) Password * #1032: Eclipse Drag and Drop Review * #864: [Web UI] Settings pages * #752: [DbDataStore] repair is very slow on big tables * #751: [DbDataStore] defrag and checkpoint are not per-table operations * #572: Unreadable errors in Web UI * #308: Add a BLE example for advertising as an Eddystone (Google) beacon * #307: CloudCallService overrides client ID * #153: Add JAX-RS to target platform * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device * Merged no issue-related Pull Requests: * #1731: Swapped commands in modem initialization * #1729: Aligned dev-env kura.properties file to the one used in devices. * #1728: Fixed a bug in the parseDhclientLeaseBlock() method. * #1719: Changes to dp generation for examples and drivers. * #1718: Disabled h2 log file by default * #1717: Fixed firewall init script * #1716: Fixed "watchdog did not stop" messages in syslog * #1713: Refreshed kuraHome variable after loading from kura.properties file. * #1711: Fixed component definition for can example * #1699: Setting an higher value for the GPIO pins. * #1697: Fixes a possible NPE in cloud services when a dp is removed. * #1688: Added custom auth request command for Ublox modems * #1687: Updated mapping between services and Ui icons. * #1682: Reduced maximum size for custom icons to 14x14 to match the other build-in icons. * #1676: Removed Karaf dependency from examples. * #1675: Implemented DEPLOY-V2 hook support * #1673: Added fallback into status bundle. * #1671: Removed the dependency existing between examples and distrib. * #1659: Fixed Telit LE 910 v2 reset * #1640: Enhanced core.status bundle. * #1624: Added basic support for Telit 910 LE v2 * #1599: Fixed startup scripts and WatchdogService * #1598: Enabled snaphsot dp builds * #1589: Added css to rotate the wires image properly. * #1496: Updated for Windows build * #1483: Added data transfer optimisation library for Drivers * #1480: Changes in Device tab. * #1460: [Testing][Refactoring] NetworkAdminServiceImpl tests, refactoring, fix * #1459: [Refactoring] Linux.position refactoring * #1458: [Testing][Refactoring] Added Camel unit tests * #1454: Cleanup org eclipse kura linux net wifi * #1450: Added exists-maven-plugin. * #1445: Added protection code to prevent null pointer in GwtWireServiceUtil. * #1443: Remove customizers * #1375: Fixed Karaf native libs loading. * #1371: Fixed regression in configuration service * #1370: Fixed connection status icon at page load. * #1368: Wires Web Ui fixes * #1318: Code Cleanups in Localization Bundle Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection will encounter a failure. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #1703: [Kura 3.1.0 QA] Wires page jumping up and down * #1700: [Kura 3.1.0 QA] Rollback doesn't restore deleted services * #1689: Instaling a dp can cause the WebUI to restart * #1663: Authentication Issue with Deploy V2 * #1657: Bluetooth notifications do not work * #1644: [Artemis] MQTT clients fail to reconnect after the broker is restarted * #1638: Kura does not support Consistent Network Device Naming * #1572: serial modbus has errors on some hardware * #1558: CommandCloudApp doesn't use received working directory parameter * #1533: MqttDataTransport client-id illegal character * #1529: OSGI console is not redirected to Eclipse IDE with Kura 3.0 * #1451: PppAuthSecrets entry removal * #1414: SCR exception running Kura Wires in Karaf * #1373: [Kura 3.0.0 QA] Configuration service: mixing configurable services with factory components * #1358: [GPS] With a USB GPS device, the position service keeps reporting the old position * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1197: [Net] Network configuration cannot be restored purely from snapshot * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot * #1193: [Wires] Component avoidance during initial placement * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1092: Possible NPE and non-working check * #1016: ConfigurationServiceImpl creates duplicate instances * #924: [Kura 2.1.0 QA enh] Non-trimmed values of configuration parameters * #923: [Kura 2.1.0 QA] eth0 search domain configuration and storage * #890: [Kura 2.1.0 QA] Snapshot management in web UI * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #654: Clean up static initialization around "modem" functionality * #651: Call to "exit()" in native code * #650: Possible bug in "LinuxUdev.c" * #645: Clean up internal dependencies in Kura * #558: Update of DPs seems not to work * #547: [Configuration] Configuration Service may miss configuration-policy=optional components * #522: [Net] Modem monitor should monitor interfaces, not modems * #520: [Net] PppFactory is not a factory and its design is wrong * #518: [Net] Modem monitor concurrency issue with multiple modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #362: Uninstaller leaves most of the files * #348: WpaSupplicantConfigReader.getWifiClientConfig() should support cases where key_mgmt scheme is not set * #329: [DEPLOY-V2] Review/refactoring needed * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation Eclipse Kura - 3.0.0 ------------------------------------------------------------------------- Added Features : * Eclipse Kura Wires https://github.com/eclipse/kura/wiki/Kura-Wires:-introduction-and-references * Eclipse Kura Drivers and Assets APIs and implementations * Contributed Eclipse Kura OPC UA driver based on Eclipse Milo * Improvements to local Web Console's usability and appearance * Added support for MQTT over Websockets * Added support for AWS IoT and Azure IoT platforms * Simple JSON is now a supported encoding option in Eclipse Kura Cloud Service * Introduced official support to Oomph installer * Added support for Fedora 25 ARM based systems Compatibility Changes: * Switched to Equinox 3.11.1 * Added support for Java 8. It is now the minimal JVM requirement to run Eclipse Kura * Dropped support for all the native libraries but ARMv6 HF and x86_64 architectures * Dropped support for Fedberry 24 systems * The configuration service will only track so called "Relevant services" so the ones that, in their component description files, will provide the ConfigurableComponent interface. The old behavior can be restored by setting the "org.eclipse.kura.core.configuration.legacyServiceTracking" property to true. Bug Fixes : * Fixed github issues: * #1335: [Kura 3.0.0 QA] User workspace plugins BREE * #1329: Need to respect /etc/network/interfaces command options * #1295: [Wires] Wires DataType lacks the KuraPayload float type * #1294: [Wires] Remove ByteValue and ShortValue as they do not map to KuraPayload metric types * #1282: Apache FileUpload Upgrade * #1277: PR #1126 breaks changes to wire graph that were not saved * #1269: [Wires] Column names in DB Store * #1246: [Wires] MQTT namespace * #1241: Changes to the heater publisher * #1240: Add JSON/Protobuf encoding option in CloudService * #1239: Change wire publisher to remove the JSON/Kura payload serialization * #1222: Commit aa2913dc1031e783d09779dae503018da55889f6 breaks asset persistent storage * #1220: [Driver] DriverRecord and AssetRecord. Clean code vs efficiency * #1216: [Wires] Sub-second Timer * #1212: [Wires] DB WireComponent improvements * #1211: [Wires] Implement regex filter WireComponent * #1210: [Wires] Implement FIFO WireComponent * #1208: [Asset] Driver read method should return void * #1206: [Driver] Driver API optimizations * #1203: [Asset] Document ASSET-V1 topic namespace * #1202: [Asset] Drop channel ID and use unique name * #1176: Kura Wires: Inconsistent design of DbServiceHelper class * #1166: Wrong order of operations in WireAsset * #1160: ClockService should ignore updates with long 'getDelay' * #1139: Factory Components Configurations not deleted from the snapshot * #1131: ConfigurableComponentTracker calls bundleContext.getService(ref) when it shouldn't * #1125: [Kura 3.0.0 M1 QA] Wires: Unexpected component configuration is shown * #1123: [Kura 3.0.0 M1 QA] Bugs in camel example publisher * #1121: [Kura 3.0.0 M1 QA] Wires: cannot add component after deleting one * #1119: [Kura 3.0.0 M1 QA] Wires DB Store partial cleanup * #1118: [Kura 3.0.0 M1 QA] Wires: dirty Component instances warning * #1116: [Kura 3.0.0 M1 QA] Wires: wire components selection * #1113: [Kura 3.0.0 M1 QA] Kura Wires doesn't work on Internet Explorer * #1107: [Kura 3.0.0 M1 QA] Issue with modal confirmation dialog(s) * #1105: [Kura 3.0.0 M1 QA] Issue with binding services * #1104: [Kura 3.0.0 M1 QA] RPi 2/3 installation package contains unwanted files * #1100: Inconsistent use of installation status strings in deployment impl * #1091: Kura doesn't properly report "ALREADY_DONE" state to Kapua * #1069: Change Package Infos in API Bundle that contain @since annotation * #1057: Kura Wires BaseAsset write issue * #1056: Kura Wires severity level based filtering issue * #1053: dhclient is not being killed if interface is switched from DHCP to static * #1041: Restructure Wire Envelope to make compatible with Kura Payload * #1033: Rename org.eclipse.kura.asset.provider.default to org.eclipse.kura.asset.utility.provider * #1026: Dragging a wire component onto the wire graphs pops up the install dialog * #1024: PR #1007 broke distribution for assets * #1022: Move AssetComponent.xml to Asset Provider * #1015: Fix Fedora target to use libudev.so.1 * #1013: Drop support for ARMv5 SF/soft float * #1003: Switch to Fedora 25 * #1000: Memory leak and concurrency issue in 'EventHandlerServlet' * #999: Refactoring: PropertiesUi must extend AbstractServicesUi * #990: Script error in installer * #959: Replace Preconditions references with Objects * #954: Fix output of properties * #932: org.eclipse.kura.asset.provider provides API and service implementation * #918: [Kura 2.1.0 QA] DEN-POS-002 Position service keeps reporting old position * #916: DEN-CONF-005 Wrong range limit for "long" * #915: [Kura 2.1.0 QA] DEN-CONF-005: Internal message when a "too big" number is entered * #914: [Web UI] Fixed fields can be edited * #911: [Kura 2.1.0 QA] SSID selection not always shows all SSIDs * #908: Web UI shows its own WLAN for connecting * #889: [Kura 2.1.0 QA] Denali Configuration ExamplePublisher error descriptions * #861: Kura's WEB bundles detection * #846: Replace INTERNAL_ERROR with suitable error code in Kura Wires * #841: Add Discouraged Access in Javadoc for INTERNAL_ERROR error code * #824: SelfConfiguringComponent are not registered properly * #817: Fix Exception Javadoc * #786: Services Search throws Exception * #770: Following the Eclipse versioning schema for OSGi * #736: Kura installer continues despite errors occurred * #725: Serial receive timeout is not forwarded to javax.comm.CommPort * #721: Unnecessary toggles eth0 interface when wlan0 interface is disabled on Raspberry Pi. * #696: FileServlet fails with NPE when there is no MetaTypeInformation * #688: Modify Kura Wires Web Copyright Header * #664: Misconfiguration of eth0 (as dhcp server) filling /var/log directory and finally crashing kura * #657: No ability to set security level with Bluetooth API * #556: Add WebSocket as alternative mqtt transport * #555: CAN bus bundle only supports 11-bit identifiers * #553: [Modbus] Refactoring of Modbus example * #550: [Modbus] String evaluation returns false * #476: Kura makes use of system properties when filtering for native code libraries which is not supported * #460: Upgrade Equinox to 3.11 and use Java 8 a minimum requirement * #372: [BLE] BluetoothGattImpl.getCharacteristics(String startHandle, String endHandle) and getServices() methods return empty list * #352: [Semantic Versioning] Enable analysis through bnd-baseline-maven-plugin * #288: [Modbus] Implement the MBAP header for TCP/IP communication * #244: [Web UI] Alphabetical ordering of metatype labels option in ListBoxes * Merged no issue-related Pull Requests: * #1370: Fixed connection status icon at page load. * #1365: Fixed deleted factory components not always being removed from snapshot (see also #1371) * #1364: Fixed factory components not being created from uploaded snapshot * #1352: Minor Wires fixes * #1350: Set security level to low * #1349: Changes to the emulator launch profiles used when cloning directly the repo * #1347: Modified emulator position. * #1344: Minor fixes regarding emulator.position and osgi.annotation. * #1343: Hidden export to CSV buttons from Wires Web UI * #1341: Modified Asset Cloudlet protocol * #1340: Fixed selinux check in kura-install.sh file. * #1339: Changes to have dev-env working. * #1337: Fixed watchdog service deactivate method * #1331: Switched equinox mirror. * #1323: Fixed handling of special characters in Wires DB * #1319: Moved Asset configuration constants and documentation out of the APIs. * #1311: Set the wire publisher qos metatype value to 0. * #1307: Add Everyware Cloud broker URL * #1302: Added opcua dp build step. * #1300: Fix modem driver code * #1289: Cleanup the payload encoder a bit * #1276: Asset cloudlet now starts immediately. * #1273: Watchdog code refactor and improvements * #1272: Improved performance of WireSupportImpl.emit() * #1266: Fixed unnecessary allocations by WireAsset * #1264: Heater demo example using Maven/BND. * #1256: Make private method static * #1238: Remove registration of service implementation classes * #1234: [Developer workspace] Updated project setup * #1227: Relax null handling, fix possible NPE, improve javadoc * #1226: Allow providing an input stream for reading XML content * #1224: Make it a functional interface * #1200: Add feature for Camel API * #1198: Changed wires component selection. * #1194: Fix iptables-restore run in background * #1192: WireEmitter/Receiver are ConsumerTypeS * #1184: Partially revert net.wifi breaking change * #1182: Removed timeout based on magic number. * #1179: Drop support for "fedorapi" * #1174: Switch default behavior to only track relevant services * #1173: OPC-UA Driver: Minor Fixes and Cleanup * #1168: Modified emulator launch. * #1154: Use window.parent instead of top in wires js and GWT parts * #1148: Enable JMX by default, allow overriding using system properties * #1144: [Developer workspace] Added 2 plugins and worspaces * #1143: Added support for enabling serial rx timeout * #1140: Improve separation of concerns for camel java example * #1136: Implement Kapua's applicationFramework/applicationFrameworkVersion * #1127: Changes to prevent exception of wires panel refresh. * #1122: Implement new Cloud Client API * #1115: Few more fixes in wires: * #1103: Added drag and drop support to the Wire Composer. * #1102: Improved drag and drop for Eclipse Marketplace. * #1099: Set of changes in EventHandlerServlet to prevent memory leak. * #1097: Check modem up in resetModem method * #1094: Modified jvm dependency. * #1090: Modified interval check in GwtNetworkServiceImpl.java. * #1088: Fixed Web Ui services search bar * #1086: OPC-UA Driver * #1085: Wires refactor 2 * #1084: Wire Service Implementation and Wire Configuration Refactoring * #1083: Removing ThrowableUtil Reference * #1076: Wire publisher can publish control messages. * #1075: Fixed a few cases in Configuration Service where NPE could be thrown * #1074: Minor Code Fixes in PropertiesUi for Wires * #1073: Renamed asset cloudlet APP_ID to ASSET-V1. * #1070: Modified log message in ConfigurationServiceImpl.java * #1058: Wires related Web2 enhancements * #1047: Extracted WireHelperService and WireSupport together to a new bundle * #1043: Modified certificates policy in Cloud Service. * #1036: Solved graphical glitch in Assets' channel definition. * #1034: Fix a bunch of C code issues * #1031: Fix wire component provider * #1029: Fix a possible NPE in the Web UI * #1028: Work around Kura sending empty string instead of null for Camel deps * #1019: Fix private members * #1010: Updates and fixes for Karaf * #1005: Fix possible exception and service leak * #1002: Fix M2E errors when directly importing Karaf projects * #998: Fix wires nulls * #988: Removed references to windows bundles in 2.1.0. * #987: Modified web2 bundle packaging. * #986: Add Eclipse Kura Nexus repository in order to fix the build * #985: Switch version of SODA Comm to 1.2.4-SNAPSHOT * #982: Activate maven batch mode by default and reduce console log * #978: Uniformed build steps, corrected some typos. * #976: Changed deb dependency requiring java 8. * #953: Convert P2 repository to Maven 2 repository * #869: Clean up and document IOUtil * #868: Fix concurrency issue in command service * #803: add pcengine-nn profile Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #1338: [Kura 3.0.0] camel.aggregation and camel.quickstart examples should be normalized * #1325: [Wires] Exception if an Channel Descriptor contains in Option of Integer type * #1201: Wifi password incorrectly read from snapshot in Access Point mode * #1197: [Net] Network configuration cannot be restored purely from snapshot * #1196: [Net] PPP password is not a (MetaType) Password * #1195: [Net] Firewall IP Forwarding rules entered in the Web UI lost on reboot * #1193: [Wires] Component avoidance during initial placement * #1161: Incorrectly configuring a component can be irreversable. * #1128: [Kura 3.0.0 M1 QA] Unable to delete manually added CamelFactory services * #1092: Possible NPE and non-working check * #1016: ConfigurationServiceImpl creates duplicate instances * #948: [Kura 2.1.0 QA] NET-ETH0-014 Wrong lease time in DHCP mode * #923: [Kura 2.1.0 QA] eth0 search domain configuration and storage * #910: [Kura 2.1.0 QA] Unable to use WLAN as WAN interface * #890: [Kura 2.1.0 QA] Snapshot management in web UI * #797: Design of ServiceUtil is broken * #771: Web UI fails with INTERNAL_ERROR when WireHelperService is not registered * #752: [DbDataStore] repair is very slow on big tables * #751: [DbDataStore] defrag and checkpoint are not per-table operations * #654: Clean up static initialization around "modem" functionality * #651: Call to "exit()" in native code * #650: Possible bug in "LinuxUdev.c" * #645: Clean up internal dependencies in Kura * #572: Unreadable errors in Web UI * #558: Update of DPs seems not to work * #547: [Configuration] Configuration Service may miss configuration-policy=optional components * #522: [Net] Modem monitor should monitor interfaces, not modems * #520: [Net] PppFactory is not a factory and its design is wrong * #518: [Net] Modem monitor concurrency issue with multiple modems * #486: Build environment broken on Windows * #406: Replace System.get* with calls to SystemService.getProperties * #362: Uninstaller leaves most of the files * #329: [DEPLOY-V2] Review/refactoring needed * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change * #307: CloudCallService overrides client ID * #297: [Status led] What connection instance controls the status led? * #253: Check if bundle contexes correctly unget services after invoking getService * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device Eclipse Kura - 2.1.0 ------------------------------------------------------------------------- Added Features : * Apache Camel Integration * New UI for Cloud Services * Support for Raspbian on Raspberry Pi 3 * Support for Fedora on Raspberry Pi 2 and 3 Bug Fixes : * Fixed github issues: * #958: [Kura 2.1.0 QA] Wrong labels in UI's DHCP&NAT configuration * #956: [Sec] Kura firewall rules bypassed with IPv6 * #941: [Kura 2.1.0 QA] Raspberry Pi 3 no-net installer * #930: [Kura 2.1.0 QA] Problems with installation of Kura on BeagleBone Black * #917: [Kura 2.1.0 QA] Wrong range messages * #912: [Kura 2.1.0 QA] Exceptions while deploying example service * #909: [Kura 2.1.0 QA] SSID selection dialog too small * #903: [Kura 2.1.0 QA] Impossible to enter multiple DNS servers * #901: [Kura 2.1.0 QA] changing username/password locks out admin access * #900: [Kura 2.1.0 QA] usbutils missing in fedberry README * #895: [Kura 2.1.0 QA] Refreshing configuration in web UI * #893: [Kura 2.1.0 QA] GPIO example bundle configuration * #883: Invalid field validation state when switching from WAN to LAN * #879: [Kura 2.1.0 QA] Raspberry Pi 3 nameserver * #877: [Kura 2.1.0 QA] eth0 netmask configuration * #876: [Kura 2.1.0 QA] Disabling eth0 interface doesn't work properly * #874: [Kura 2.1.0 QA] eth0 DNS server configuration * #867: [Kura 2.1.0 QA] Ethernet interface gateway configuration on Raspberry Pi 3 * #860: [Kura 2.1.0 QA] JUnit in Raspberry Pi 3's installation package * #859: [Kura 2.1.0 QA] Installation warnings/errors on Raspberry Pi 3 * #851: [Web-UI] Label is sent instead of value for metatype parameters with options * #835: [Kura 2.1.0] Bind/Named service doesn't work properly on Fedora * #793: [Kura 2.1.0] QA for the User Workspace * #776: Serialization issue in cloud window * #767: Change Housekeeping schedule from scheduleAtFixedRate to scheduleWithFixedDelay * #753: libhidapi not correctly compiled for armv5 * #743: WLAN not detected as WLAN on Fedberry * #742: Unable to establish stable network connection on Fedberry * #732: Unable to configure CloudService instance when component gets unregistered * #724: [Release 2.1.0] Check API packages * #716: Create a simple Camel Java DSL based example publisher * #692: Drop default to 255 characters on data entry * #691: NPE when CloudService isn't configured * #683: Control Prefix in Request/Response * #660: [kura-build] jdk.dio deployment fails in Hudson * #649: Missing copyright headers * #642: Raspbian Pi3 * #641: [Camel] KuraCloudConsumer - Failed to subscribe exception * #640: [Modem] NoClassDefFoundError: Could not initialize class org.eclipse.kura.linux.net.modem.SupportedUsbModems * #635: ExecCommand in org.eclipse.kura.linux.bluetooth.BluetoothAdapterImpl Index Out Of Bounds * #627: Fix Bundle-Vendor to "Eclipse Kura" * #619: Duplicate version of maven-antrun-plugin * #618: Recent CR/LF fix causes 182 file modification pending * #613: Recent addition of checkstyle fails the build * #603: Can "json 20090211" be removed? * #599: WebUI fails completely is `PositionService` is not registered * #596: Replace all calls to ConfigurationAdmin.getConfiguration(String) * #595: ComponentMetaTypeBundleTracker is processing every bundle twice on startup * #592: Again Java 7 code in BREE 6 bundle * #589: [Camel] Camel related exceptions on Kura startup * #581: Missing Package Info in few packages in API Bundle * #573: Commit 41c3180 breaks data entry * #571: Convert files from dos 2 unix format * #564: [Configuration] ConfigurationService doesn't set properly the kura.service.pid * #562: Services UI not getting updated with new properties * #557: Add SLF4J jcl-over-slf4j * #548: Kura 2 Webui on BeagleboneBlack Problem * #544: Web UI shows red-connector although state is CONNECTED * #540: [Web UI] Empty Integer field in a configuration (not required) is causing a NumberFormatException * #539: [Cloud] Required changes in CloudServiceFactory * #521: Device -> Threads shows empty list * #515: [Web UI] Implement Cloud Services UI * #511: Upgrade SLF4J to 1.7.21 * #509: [Web 2] ServicesUi validation * #497: SystemServiceImpl uses method from Java 7 but declares a BREE of Java 6 * #496: mToolkit Eclipse Plugin does not work under Eclipse Neon * #488: Command cloud App Null Pointer Exception * #485: Change b02bc9a7615ca559349f2b05485ea84fd80d6e77 breaks deployment of "sun.misc" bundles * #473: org.eclipse.kura.linux.net.modem.ModemDriver uses Java 7 API but has BREE of Java 6 * #467: Web UI cannot handle Integer with cardinality 0/optional * #465: CloudService.isConnected not shown in Web UI * #461: Registering a component which has a PID without dot crashes the Web UI 2 * #451: setting a payload metric to null should throw an exception immediately * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service * #419: Migrate ASF camel-kura code to Eclipse * #403: Fix javadoc for the getKuraVersion() method of the SystemService. * #396: iwScanTool fails to parse scan results * #343: [Web2]: Setting the "name" property to anything different than the "id" sets an empty value * #342: [Configuration] Support multiple configurations for SelfConfiguringComponentS * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections * #337: [Web2]: Field validation errors not shown * #326: org.eclipse.kura.web2 is missing about.html * #321: No support for systemd based systems * #318: There should be Oomph based setups for Kura * #315: The Kura documentation should mention the default login credentials admin/admin * #314: The Camel Quickstart example is not working * #281: Add XML routes configuration per Camel CloudService * #265: Camel Examples: review * #262: Maven failure when dev-env isn't built * #257: KuraComponent can't resolve its collaborators * #234: [Web UI] web2 network configuration glitch * #231: Create Maven plugin capable of wrapping regular bundles in DP packages * #221: [Camel] Do we need a Camel API in the org.eclipse.kura.api bundle? * #216: [Test] Test Kura on RaspberryPi 3 * #205: All languages from Camel Core should be loaded by CamelRouter * #204: All data formats from Camel Core should be loaded by CamelRouter * #189: [Camel] Camel integration in the Kura CloudService * #119: [Camel] Migrate CamelRouter tests from Rhiot to Kura * Merged no issue-related Pull Requests: * #962: Added libudev for rhel based devices * #928: [Web-Ui] Fixed typo in the network config section * #898: Solved modem reset failure. * #855: Modified wrong entry in snapshot 0s * #816: Set the 'kura.ui.service.hide' property * #810: Remaining changes to Camel Web UI * #805: Prepend kura- to modem log files. * #802: Try a fix for the startup exception, missing "kura-cloud" * #798: Add Fedora 24 based ARM7 native library * #765: Reverts change in commit 7704d180296551b0acb68044f7cd6b4c3e77f56a * #761: Allow camel component to be initialized * #756: Allow Camel modules to gracefully handle missing dependencies * #755: Allow automatic conversion from Map to KuraPayload * #745: Solved possible IllegalArgumentException due to null pid * #744: Fixed wifi scan in AP mode * #739: Solved possible 404 error when downloading snapshot * #730: WiFi switching between Station and Access Point is unreliable * #720: Fix wifi issues 2.1.0 * #717: Lower camel imports to 2.17.0 * #700: Fix Watchdog disabling bug in WatchdogService. * #699: Add DependencyManagement to Camel Examples * #698: Fix ble process leak * #697: Export ConfigurableComponent in service xml * #694: Fix Camel imports * #662: Implement a workaround for issue #590 * #643: Clean up imports for Camel * #630: Minor cleanups to the Linux ClockServiceImpl * #625: Kura should not publish modified artifacts under "org.eclipse" namespace * #624: Let example services export ConfigurableComponent * #607: Start the Web UI component immediately * #605: Fix a few resource leaks * #602: Initial support for building a version for PC Engines APU / Debian 8 * #594: Implement missing method 'unsetSystemService' * #578: Cleanup dead code * #563: clean up some source code issues * #560: Fixed bug on ConfigurationService about kura.service.pid * #552: Support for RPi running Fedora via Fedberry, Pidora, etc. * #546: Minor fixes for the startup scripts * #542: Re-use existing code to parse kura.properties * #530: Fix service leak in ComponentUtil * #528: Fix the lookup of the default value, now done by id. * #513: Follow Eclipse trademark guidelines * #508: Refactor Camel router * #501: Enh build deploy Know Issues : * The implementation of the CryptoService performs encryption using a password that is hardcoded and published. * Kura can be run in a Java 8 VM, but current OSGi container does not support bundles with manifests that specify a "Bundle-RequiredExecutionEnvironment" equal to "JavaSE-1.8". * The old GPS position will continue to be shown in the status overview even after the disabling of the static position reporting. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #948: [Kura 2.1.0 QA] NET-ETH0-014 Wrong lease time in DHCP mode * #923: [Kura 2.1.0 QA] eth0 search domain configuration and storage * #918: [Kura 2.1.0 QA] DEN-POS-002 Position service keeps reporting old position * #916: [Kura 2.1.0 QA] DEN-CONF-005 Wrong range limit for "long" * #915: [Kura 2.1.0 QA] DEN-CONF-005: Internal message when a "too big" number is entered * #914: [Web UI] Fixed fields can be edited * #911: [Kura 2.1.0 QA] SSID selection not always shows all SSIDs * #910: [Kura 2.1.0 QA] Unable to use WLAN as WAN interface * #908: [Kura 2.1.0 QA] Web UI shows its own WLAN for connecting * #890: [Kura 2.1.0 QA] Snapshot management in web UI * #889: [Kura 2.1.0 QA] Denali Configuration ExamplePublisher error descriptions * #778: [Net] Refactor needed in org.eclipse.kura.core.net * #752: [DbDataStore] repair is very slow on big tables * #751: [DbDataStore] defrag and checkpoint are not per-table operations * #737: Fedora distribution fails to start up * #736: Kura installer continues despite errors occurred * #725: Serial receive timeout is not forwarded to javax.comm.CommPort * #721: Unnecessary toggles eth0 interface when wlan0 interface is disabled on Raspberry Pi. * #696: FileServlet fails with NPE when there is no MetaTypeInformation * #664: Misconfiguration of eth0 (as dhcp server) filling /var/log directory and finally crashing kura * #654: Clean up static initialization around "modem" functionality * #651: Call to "exit()" in native code * #650: Possible bug in "LinuxUdev.c" * #645: Clean up internal dependencies in Kura * #572: Unreadable errors in Web UI * #558: Update of DPs seems not to work * #553: [Modbus] Refactoring of Modbus example * #550: [Modbus] String evaluation returns false * #547: [Configuration] Configuration Service may miss configuration-policy=optional components * #522: [Net] Modem monitor should monitor interfaces, not modems * #520: [Net] PppFactory is not a factory and its design is wrong * #518: [Net] Modem monitor concurrency issue with multiple modems * #406: Replace System.get* with calls to SystemService.getProperties * #362: Uninstaller leaves most of the files * #329: [DEPLOY-V2] Review/refactoring needed * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change * #307: CloudCallService overrides client ID * #297: [Status led] What connection instance controls the status led? * #288: [Modbus] Implement the MBAP header for TCP/IP communication * #253: Check if bundle contexes correctly unget services after invoking getService * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation * #172: Modem: manually killing pppd with Kura running never triggers a modem reset * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only Eclipse Kura - 2.0.2 ------------------------------------------------------------------------- Bug Fixes : * Merged no issue-related Pull Requests: * #653: Hotfixes for WiFi for the 2.0.2 service release. This addresses Kura not restarting hostapd if the service has stopped for some reason. * #652: This is a hotfix for a process leak in Bluetooth LE when calling hcidump. Know Issues : * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #467: Web UI cannot handle Integer with cardinality 0/optional * #465: CloudService.isConnected not shown in Web UI * #462: ConfigurationServiceImpl cannot handle cardinality >1 for SelfConfiguringComponent * #461: Registering a component which has a PID without dot crashes the Web UI 2 * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service * #396: iwScanTool fails to parse scan results * #362: Uninstaller leaves most of the files * #355: [Semantic Versioning] org.eclipse.kura.net.wifi version should be increased from 1.2.0 to 1.3.0 * #343: [Web2]: Setting the "name" property to anything different than the "id" sets an empty value * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections * #337: [Web2]: Field validation errors not shown * #329: [DEPLOY-V2] Review/refactoring needed * #314: The Camel Quickstart example is not working * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change * #307: CloudCallService overrides client ID * #299: On Red Hat Fedora, network-scripts can contain double quotes * #297: [Status led] What connection instance controls the status led? * #288: [Modbus] Implement the MBAP header for TCP/IP communication * #262: Maven failure when dev-env isn't built * #257: KuraComponent can't resolve its collaborators * #253: Check if bundle contexes correctly unget services after invoking getService * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH * #234: [Web UI] web2 network configuration glitch * #224: Fixed modem reset and kura restart issues for gps * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation * #174: Networking: check why sometimes eth0 is toggled on wlan0 reconfiguration * #172: Modem: manually killing pppd with Kura running never triggers a modem reset * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only * #77: Data Service will not connect for other locale than an english one Eclipse Kura - 2.0.1 ------------------------------------------------------------------------- Bug Fixes : * Fixed github issues: * #473: org.eclipse.kura.linux.net.modem.ModemDriver uses Java 7 API but has BREE of Java 6 * #468: [Web] NPE in GwtNetworkServiceImpl * #464: Beaglebone install script not creating /etc/sysconfig * #393: [NN] NN profiles are broken in Kura 2.0.0 * #373: Kura 2.0.0 distribution for Raspberry-Pi includes emulator.gpio instead of linux.gpio * #340: [Configuration] Metatype not updated in the Web UI * #338: [Web2]: String input forced to a maximum length of 255 * #316: Debian package should declare dependency on java * #296: [Web UI] Status | Connection: if the connection username is not set, "null" is shown * #290: [Web UI] Refresh button in network configuration deselects the currently selected interface * #289: [Web UI] Wireless Password disappears after verification * #275: [Dev Env] Add org.eclipse.kura.linux.bluetooth to the target-platform. * #242: [Web UI] Help is not always visible in the new web ui * Merged no issue-related Pull Requests: * #489: Modified check for crypto value in isDefaultPassword. * #484: Modified wrong references in some snapshots, modified sslManager service to perform a different check for the default password and the password change. * #483: Modified launch configurations. * #480: Fix firewall issues * #475: Hotfix ble fixes * #441: JDK DIO: disable verbose logging from armv5_sf and x86_64 libraries. * #440: Modified the configuration service to prevent the generation of empty snapshots. * #439: Refactored code, modified behavior with gpio calculation from base address + offset. * #438: Added more checks in ServicesUI to prevent possible exception. Removed servicesUi refresh at every click in status section. * #431: Fix missing license headers * #428: Fix missing camel bundle in dev workspace * #417: Fix logging of exceptions and clean up other logging calls * #404: Fix a possible NPE followed by a NCDFE when system property is missing * #402: Fix two NullPointerExceptions and improve the error output * #400: Fix build warnings * #395: Remove dependency on slf4j-log4j12 * #388: Modified snapshot_0s in order to have memory persistance for in-flight messages. * #382: Use a copy-on-write list in order to support concurrent modifications * #361: Use Import-Package in preference of Require-Bundle * #351: Pom cleanup * #347: Reset the original state of the accessible flag * #346: Clean up the error output to actually print out stack traces * #336: Corrected jacoco version due to build failure in JDK8 * #328: Fix output of executed commands * #325: Fix a possible Context Class Loader leak * #320: Provide Oomph setup and clean up build issue Know Issues : * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. * #467: Web UI cannot handle Integer with cardinality 0/optional * #465: CloudService.isConnected not shown in Web UI * #462: ConfigurationServiceImpl cannot handle cardinality >1 for SelfConfiguringComponent * #461: Registering a component which has a PID without dot crashes the Web UI 2 * #444: Multiple Cloud Support - Web UI does not allow to select new installed cloud service * #396: iwScanTool fails to parse scan results * #362: Uninstaller leaves most of the files * #355: [Semantic Versioning] org.eclipse.kura.net.wifi version should be increased from 1.2.0 to 1.3.0 * #343: [Web2]: Setting the "name" property to anything different than the "id" sets an empty value * #339: [Web UI] The Disconnect button in the Status menu disconnects all connections * #337: [Web2]: Field validation errors not shown * #329: [DEPLOY-V2] Review/refactoring needed * #314: The Camel Quickstart example is not working * #311: [Multiple Cloud Connections] Spurious component reactivations upon configuration change * #307: CloudCallService overrides client ID * #299: On Red Hat Fedora, network-scripts can contain double quotes * #297: [Status led] What connection instance controls the status led? * #288: [Modbus] Implement the MBAP header for TCP/IP communication * #262: Maven failure when dev-env isn't built * #257: KuraComponent can't resolve its collaborators * #253: Check if bundle contexes correctly unget services after invoking getService * #235: LinuxNetworkUtil#toolExists() should check for tool's existence in PATH * #234: [Web UI] web2 network configuration glitch * #224: Fixed modem reset and kura restart issues for gps * #222: CloudConnectionStatusServiceImpl does not cancel workers on component deactivation * #174: Networking: check why sometimes eth0 is toggled on wlan0 reconfiguration * #172: Modem: manually killing pppd with Kura running never triggers a modem reset * #108: CloudCallServiceImpl - call methods setting requester.client.id to #client-id sends response to local device * #104: org.eclipse.kura.linux.net.ConnectionInfoImpl is IPv4 only * #77: Data Service will not connect for other locale than an english one Eclipse Kura - 2.0.0 ------------------------------------------------------------------------- Added Features : * Added support for multiple connections * Added support for Wi-Fi Multi Mode * Created a new web UI bundle named org.eclipse.kura.web2 that integrates GWT 2.7 and GwtBootstrap 3 technologies * Updated bluetooth APIs and added support for Bluez 5.x * Initial integration of RedHat's Camel stack * Created a Kura applications section inside the Eclipse marketplace and added support in the local web UI for the application install via drag-and-drop * Created SenseHat example project * Updated the SensorTag Example project exposing buzzer and leds * Created the beacon.scanner project * Native libraries now support x86_64 * Reviewed/refactored the GPS position service Bug Fixes : * Fixed github issues #78, #82, #96, #98, #112, #113, #114, #116, #120, #121, #127, #128, #129, #131, #134, #138, #139, #141, #143, #167, #169, #177, #179, #182, #184, #187, #188, #193, #198, #199, #201, #202, #203, #209, #212, #214, #215, #218, #227, #228, #229, #230, #233, #238, #241, #250, #252, #254, #255, #256, #258, #260, #267, #270, #271, #272, #279, #284, #302, #309 Know Issues : * Multiple connections: updating a service (e.g. MqttDataTransport) of a connection has the effect to cause the unwanted reactivation of the next higher layer service (i.e. DataService) of the other connection(s). This in turn will cause the reactivation of all dependent components. This is not desired and not yet understood (Equinox bug?). See also Github issue #311. * Modem: Ublox Lisa U201 may not be able to establish PPP connection when CHAP/PAP authentication is required. * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipset. * The reference JVMs are Oracle Java SE Embedded version 7 Update 40 and Java SE Embedded version 8 Update 65. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Web UI may hang when configuration snapshot is uploaded. This happens because HTTP connection is lost due to toggling of the network interface which happened even if network configuration hasn't been modified. Eclipse Kura - 1.4.0 ------------------------------------------------------------------------- Added Features : * Grouped Web UI SSL configuration in a single place under 'Settings' * Modified the Web UI adding a check in order to block SSIDs longer than 32 characters * Rolled-back Web UI filtering of SSID * Added some security headers to the Web UI * Refactored security related tabs in the Web UI * Added property to the WatchdogService to specify the watchdog device * Modified build in order to include checks for Java 8 compact 2 compliance * Introduced new deployment application (named DEPLOY-V2) that improves updates download from the cloud platform * New firewall management, now based on iptables-save and iptables-restore * Firewall: allowed open port entries for tcp and udp on the same port * Firewall: enabled the support for port ranges when defining open port entries * Added support for Ublox SARA-U2 modem * Added support to switch between AP and station mode on radios supported by the 'bcmdhd' kernel module * Emulator bundle split into 6 separate bundles, one for each function * Reviewed no-network profiles: removed net.admin bundle and linux.net. Now those bundles are replaced by emulator.net * Linux build date/version is now published in the birth certificate as part of the os.version metric * Improvements to the Development Environment * ConfigurationService: treat an OSGi ManagedService as a ConfigurableComponent * Updated documentation Bug Fixes : * Fixed github issue #80 * Fixed github issue #84 * Fixed github issue #85 * Fixed github issue #87 * Fixed configuration rollback to snapshot 0 * Fixed toggling WiFi interface when Ethernet interface is reconfigured * Better Web UI exception handling when manually (dis)connecting to the Cloud * Added various null pointer checks * Started work to fix warnings emitted by Sonar * Fixed JUnit tests * Fixed GPIO example * Fixed bug when image in metatype has no size * Fixed and improved the BLE TI SensorTag example Know Issues : * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The kernel version was "Linux raspberrypi 3.18.11-v7+ #781 SMP PREEMPT Tue Apr 21 18:07:59 BST 2015 armv7l GNU/Linux". Note that on the kernel "Linux version 4.1.7-v7+ (dc4@dc4-XPS13-9333) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #817 SMP PREEMPT Sat Sep 19 15:32:00 BST 2015" has a bug on gatttool and the BLE connection failes. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipest. * The reference JVMs are Oracle Java SE Embedded version 7 Update 40 and Java SE Embedded version 8 Update 65. * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Web UI may hang when configuration snapshot is apploaded. This happens because HTTP connection is lost due to toogling of the network interface which happened even if network configuration hasn't been mo dified. Eclipse Kura - 1.3.0 ------------------------------------------------------------------------- Added Features : * API updates (Security, GPIOService) * Enhanced web UI security, which includes: * XSRF protection in all servlets * Different management of user sessions * Arbitrary file writes protection in file servlet for zip uploads * XSS on wireless SSID in network servlet * Command injection on network servlet * Password protection in client UI, in order to prevent access to secrets by unauthorized users * Sanitization of user and system strings in order to prevent malicious attacks * Ability to configure pairwise ciphers in AP mode in web UI. * Ability to stop/start bundles from web UI. * Ability to embed ConfigurableComponent icon within bundle, instead for requiring https location. * Added support for Telit LE910 modems. * Added test code for XML marshalling/unmarshalling. * Removed Xss option from start scripts. This JVM option has a know bug in OpenJDK. * Improvements to usability of Emulator. * Improvements to the Development Environment. Know Issues : * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipest. * The reference JVM is Oracle Java SE Embedded version 7 Update 40. Later versions (including Oracle Java SE Embedded version 8 Update 33) may be affected by a ProcessBuilder memory leak [1] * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud. [1] https://bugs.openjdk.java.net/browse/JDK-8054841 Eclipse Kura - 1.2.2 ------------------------------------------------------------------------- Added Features : * Added support for Ubuntu 14.04. Note, this is just the initial support for Ubuntu, there are no installation files in this release. Known Issues : * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipest. * The reference JVM is Oracle Java SE Embedded version 7 Update 40. Later versions (including Oracle Java SE Embedded version 8 Update 33) may be affected by a ProcessBuilder memory leak [1] * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud. [1] https://bugs.openjdk.java.net/browse/JDK-8054841 Eclipse Kura - 1.2.1 ------------------------------------------------------------------------- Added Features : * Added Bluetooth LE Beacon Service * Example: org.eclipse.kura.example.beacon * Reduced number of dependencies for Bluetooth LE bundle * Added support for non cfg80211 wifi modules * Added support for wifi on Raspberry Pi * Added support for Oracle Java 8 SE Compact 2 Profile runtime * Replaced IBM javax.usb implementation with usb4java * Refactor and optimization of SSL Manager * Improved security during keystore loading in SSL Manager * Refactor of ConfigurationService * Replace JAXB XML Parser with a custom one * Startup time improvements due to various code optimizations and uncompressed jars * Web UI: added the possibility to specify a custom web interface user * Web UI: split certificate management in two separate tabs Bug Fixes : * Web UI: fixed wrong units for memory Known Issues : * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * WiFi on Raspberry Pi only tested with WiPi WiFi Dongle (Realink RT5370 chipset) and official Pi USB WiFi Dongle (Broadcom BCM43143 chipset). AccessPoint WiFi mode not working for Broadcom chipest. * The reference JVM is Oracle Java SE Embedded version 7 Update 40. Later versions (including Oracle Java SE Embedded version 8 Update 33) may be affected by a ProcessBuilder memory leak [1] * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud. [1] https://bugs.openjdk.java.net/browse/JDK-8054841 Eclipse Kura - 1.2.0 ------------------------------------------------------------------------- Added Features: * Added support for securing Kura * Revised org.eclipse.kura.crypto API. * New org.eclipse.kura.certificate API to enable validation of signed requests from the cloud. * Minimal implementation of the org.eclipse.kura.crypto API. * Implementation of the org.eclipse.kura.certificate API. * Encryption of passwords in snapshot files. * Snapshot encryption. * Improved management and security of the keystore used for the MQTT SSL connection. * Added support for the Raspberry Pi B+ and the Raspberry Pi 2. * Added support for Bluetooth Low Energy (see Known Issues section below). * API: org.eclipse.kura.bluetooth * Example: org.eclipse.kura.example.ble.tisensortag * Added OSGi console commands (get/setkuraloglevel) to control the Kura logger. Bug Fixes: * Web UI: fixed wrong time units in the DHCP lease interval. * Web UI: filter 5GHz channels when displaying WiFi scan results. * Upgrade Deployment Package: remove the old Kura installation directory. * MqttDataTransport configuration: changed default MQTT protocol version to 3.1.1. * CloudService: even if gzip compression is enabled, publish the uncompressed MQtt payload if its size is less than the compressed payload size. * Network: Reduced executions of external ifconfig processes. * Network: Fixed WiFi background scan configuration. Known Issues: * BLE only tested on the Raspberry Pi B with a Broadcom BCM20702 USB dongle and the TI SensorTag. The only working version of BlueZ is 4.101. The deb package is not available from Raspbian so it must be compiled from sources. * The Intel Edison platform is still a work in progress. * The reference JVM is Oracle Java SE Embedded version 7 Update 40. Later versions (including Oracle Java SE Embedded version 8 Update 33) may be affected by a ProcessBuilder memory leak [1] * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud. [1] https://bugs.openjdk.java.net/browse/JDK-8054841 Eclipse Kura - 1.1.2 ------------------------------------------------------------------------- Bug Fixes: * Fixed JVM memory leak by making sure all stream are closed and the streams associated to the stdout and stderr of external processes are consumed asynchronously * Overall optimization of the network related bundles by removing unnecessary executions of external processes * Fixed MANIFESTs removing unused imports and fixing Import-Package version ranges to comply with OSGi Semantic Versioning * Ppp0 connection not starting after a fresh install * Modem did not recover the connection when the antenna is unplugged * Avoid starting two Kura instances * Rolling back to snapshot 0 does not change the modem configuration on the Minigateway * Don't allow to set the gateway on LAN interfaces * When reconfiguring Wifi from Station to Access Point, DHCP&NAT tab gets enabled only after clicking on the 'Wireless' tab * Since we don't support 802.11a, do not allow this in configuration * Poweroff command fails at 'Stopping Kura' * Disable snmpd to avoid excessive flash writes on raw-flash devices Known Issues: * The reference JVM is Oracle Java SE Embedded version 7 Update 40. Later versions (including Oracle Java SE Embedded version 8 Update 33) may be affected by a ProcessBuilder memory leak [1] * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface * When first modem configuration is submitted, unconfigured cellular interface for serial modem (e.g. HE910) is not being replaced by ppp0 interface. Both ppp0 and HE910 interfaces are shown in the Web Admin. * Gateway needs to be rebooted for static GPS coordinates to be published to the cloud. [1] https://bugs.openjdk.java.net/browse/JDK-8054841 Eclipse Kura - 1.1.1 ------------------------------------------------------------------------- Added Features: * Added configurable CommandService to password-protect command execution * Added support to reset WiFi if it cannot be enabled * Added selection of the MQTT protocol version to the MqttDataTransport configuration Bug Fixes: * Fixed ppp0 interface disappeared from Web UI * Improved tips in the cellular modem advanced options and changed default values * Fixed bug 452499: Kura Debian package name should be lower case * Fixed org.eclipse.kura.linux.position not setting the track heading parameter * Fixed org.eclipse.kura.linux.position to correctly select the GPS receiver * Fixed org.eclipse.kura.linux.usb to better handle removal of USB devices * Fixed org.eclipse.kura.linux.net to properly track USB add/remove events and stale devices * Fixed org.eclipse.kura.net.admin to properly track modems * Fixed org.eclipse.kura.net.admin to keep resetting the modem if PPP link cannot be established * Fixed minor issues Known Issues: * Hardware watchdog: not implemented on all platforms * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface Eclipse Kura - 1.1.0 ------------------------------------------------------------------------- Added Features: * OpenJDK Device I/O integration * Added org.eclipse.kura.example.gpio example using OpenJDK Device I/O * Added RPI B+ distribution * Display warning in the WEB UI if the user attempts to enable more than one WAN interface * Modem IMEI and SIM IMSI/ICCID published in the birth certificate * Improved documentation on the Eclipse Kura Wiki * Upgraded to Google Protocol Buffers 2.6.0 (adding union types) * Display client ID in the WEB UI Status page Bug Fixes: * Upticked API package versions to 1.0.0 * Fixed DNS issue when DNS servers are provided in the configuration * Fixed 'iw' scan problem (IBSS capability) * Fixed a MetaTypeBundleTracker issue slowing down the Kura startup * Added a minimum value of two minutes for the modem reset interval * Improved robustness of the Kura upgrade scripts * Upgraded to Paho 1.0.1 (many bug fixes) * Fixed uncaught exception preventing network interfaces being displayed in the WEB UI * Set Paho client callback to null before terminating the client * Removed 'old' native library directories * Fixed WEB UI username/password lost for the in-memory configuration of HSQLDB * Fixed HIDAPI bundle * Fixed HSQLDB exception due to large system time adjustments * Merged pull requests and contributions sent in the form o diff files to the mailing list * Added 'telnet' to the list of 'apt' dependencies Known Issues: * Hardware watchdog: not implemented on all platforms * Reliagate 50-21: Using eth1 and Windows 7 to access the webui does not work over some network topologies - OSX or Linux are recommended to access the webui in this rare case * Only one WAN interface is currently supported. A warning in displayed in the WEB UI if the user attempts to enable more than one WAN interface Eclipse Kura - Initial Version ------------------------------------------------------------------------- Features: * Runs on Java SE 7 Embedded and OpenJDK 7 * Core OSGi runtime using Eclipse Equinox v3.8.1 * API support including: * Clock (both system clock syncing via NTP and hardware clock sync) * Cloud connections (MQTT) with local store and forward capabilities to handle disconnected states as well as Google Protobuf message packing * Service configuration locally and remotely via OSGi ConfigAdmin with Metatype support * Network status including IP address, netmask, DNS, gateway, and hardware types * Network administration: modifying network configuration including IP address, netmask, DNS, gateway, DHPC servers, Nat/Masq, firewall, wifi AP, wifi station, SSID, wifi security types, wifi channel, and cellular modems, and routing tables. * GPS configuration * USB devices including dynamic detection * OSGi Deployment Package support * Local configuration web UI * Eclipse based emulator for local host PC development/testing including support for OSX and Linux * Remote configuration and device management capabilities when connected to Eurotech's Everyware Cloud * Support for remote OSGi console and bundle deployment from Eclipse Known Issues: * Hardware watchdog: not implemented on all platforms * Reliagate 50-21: Using eth1 and Windows 7 to access the webui does not work over some network topologies - OSX or Linux are recommended to access the webui in this rare case * Only one WAN interface is currently supported. Make sure you never have multiple WAN interfaces defined or it could result in network connectivity issues ================================================ FILE: kura/distrib/aarch64-core/pom.xml ================================================ 4.0.0 distrib org.eclipse.kura 6.0.0-SNAPSHOT .. aarch64-core pom ../ aarch64 ${kura.arch} ${kura.arch} kura-core arm64 false maven-dependency-plugin maven-resources-plugin org.vafer jdeb ================================================ FILE: kura/distrib/core-dp/pom.xml ================================================ 4.0.0 distrib org.eclipse.kura 6.0.0-SNAPSHOT .. core-dp pom ../ org.apache.maven.plugins maven-dependency-plugin core-dp package copy-dependencies org.eclipse.kura.protocol.modbus, org.eclipse.kura.driver.s7plc, org.eclipse.kura.driver.eddystone, org.eclipse.kura.driver.ibeacon, org.eclipse.kura.driver.gpio, org.eclipse.kura.driver.ble.xdk, org.eclipse.kura.db.sqlite.provider, org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider, org.eclipse.kura.cloudconnection.raw.mqtt.provider dp ${project.build.directory} ================================================ FILE: kura/distrib/eclipse_license.txt ================================================ Copyright (c) ${dates} ${owner} This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: ${contributor} ================================================ FILE: kura/distrib/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/distrib/notice.html ================================================ Eclipse Foundation Software User Agreement

Eclipse Foundation Software User Agreement

November 22, 2017

Usage Of Content

THE ECLIPSE FOUNDATION MAKES AVAILABLE SOFTWARE, DOCUMENTATION, INFORMATION AND/OR OTHER MATERIALS FOR OPEN SOURCE PROJECTS (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE TERMS AND CONDITIONS OF THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT USE THE CONTENT.

Applicable Licenses

Unless otherwise indicated, all Content made available by the Eclipse Foundation is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is provided with this Content and is also available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

Content includes, but is not limited to, source code, object code, documentation and other files maintained in the Eclipse Foundation source code repository ("Repository") in software modules ("Modules") and made available as downloadable archives ("Downloads").

  • Content may be structured and packaged into modules to facilitate delivering, extending, and upgrading the Content. Typical modules may include plug-ins ("Plug-ins"), plug-in fragments ("Fragments"), and features ("Features").
  • Each Plug-in or Fragment may be packaged as a sub-directory or JAR (Java™ ARchive) in a directory named "plugins".
  • A Feature is a bundle of one or more Plug-ins and/or Fragments and associated material. Each Feature may be packaged as a sub-directory in a directory named "features". Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of the Plug-ins and/or Fragments associated with that Feature.
  • Features may also include other Features ("Included Features"). Within a Feature, files named "feature.xml" may contain a list of the names and version numbers of Included Features.

The terms and conditions governing Plug-ins and Fragments should be contained in files named "about.html" ("Abouts"). The terms and conditions governing Features and Included Features should be contained in files named "license.html" ("Feature Licenses"). Abouts and Feature Licenses may be located in any directory of a Download or Module including, but not limited to the following locations:

  • The top-level (root) directory
  • Plug-in and Fragment directories
  • Inside Plug-ins and Fragments packaged as JARs
  • Sub-directories of the directory named "src" of certain Plug-ins
  • Feature directories

Note: if a Feature made available by the Eclipse Foundation is installed using the Provisioning Technology (as defined below), you must agree to a license ("Feature Update License") during the installation process. If the Feature contains Included Features, the Feature Update License should either provide you with the terms and conditions governing the Included Features or inform you where you can locate them. Feature Update Licenses may be found in the "license" property of files named "feature.properties" found within a Feature. Such Abouts, Feature Licenses, and Feature Update Licenses contain the terms and conditions (or references to such terms and conditions) that govern your use of the associated Content in that directory.

THE ABOUTS, FEATURE LICENSES, AND FEATURE UPDATE LICENSES MAY REFER TO THE EPL OR OTHER LICENSE AGREEMENTS, NOTICES OR TERMS AND CONDITIONS. SOME OF THESE OTHER LICENSE AGREEMENTS MAY INCLUDE (BUT ARE NOT LIMITED TO):

IT IS YOUR OBLIGATION TO READ AND ACCEPT ALL SUCH TERMS AND CONDITIONS PRIOR TO USE OF THE CONTENT. If no About, Feature License, or Feature Update License is provided, please contact the Eclipse Foundation to determine what terms and conditions govern that particular Content.

Use of Provisioning Technology

The Eclipse Foundation makes available provisioning software, examples of which include, but are not limited to, p2 and the Eclipse Update Manager ("Provisioning Technology") for the purpose of allowing users to install software, documentation, information and/or other materials (collectively "Installable Software"). This capability is provided with the intent of allowing such users to install, extend and update Eclipse-based products. Information about packaging Installable Software is available at http://eclipse.org/equinox/p2/repository_packaging.html ("Specification").

You may use Provisioning Technology to allow other parties to install Installable Software. You shall be responsible for enabling the applicable license agreements relating to the Installable Software to be presented to, and accepted by, the users of the Provisioning Technology in accordance with the Specification. By using Provisioning Technology in such a manner and making it available in accordance with the Specification, you further acknowledge your agreement to, and the acquisition of all necessary rights to permit the following:

  1. A series of actions may occur ("Provisioning Process") in which a user may execute the Provisioning Technology on a machine ("Target Machine") with the intent of installing, extending or updating the functionality of an Eclipse-based product.
  2. During the Provisioning Process, the Provisioning Technology may cause third party Installable Software or a portion thereof to be accessed and copied to the Target Machine.
  3. Pursuant to the Specification, you will provide to the user the terms and conditions that govern the use of the Installable Software ("Installable Software Agreement") and such Installable Software Agreement shall be accessed from the Target Machine in accordance with the Specification. Such Installable Software Agreement must inform the user of the terms and conditions that govern the Installable Software and must solicit acceptance by the end user in the manner prescribed in such Installable Software Agreement. Upon such indication of agreement by the user, the provisioning Technology will complete installation of the Installable Software.

Cryptography

Content may contain encryption software. The country in which you are currently may have restrictions on the import, possession, and use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check the country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted.

Java and all Java-based trademarks are trademarks of Oracle Corporation in the United States, other countries, or both.

================================================ FILE: kura/distrib/pom.xml ================================================ 4.0.0 org.eclipse.kura distrib 6.0.0-SNAPSHOT pom distrib https://eclipse.dev/kura/ aarch64-core x86_64-core 1.14 UTF-8 ${project.basedir} ${maven.build.timestamp} /opt/eclipse kura kura-6 base 1.6.900 KURA_${project.version} ${kura.version} ${kura.install.dir}/${kura.symlink} ${kura.home}/framework ${kura.home}/user ${kura.home}/plugins ${kura.home}/packages ${kura.home}/data ${kura.home}/snapshots ${kura.home}/console.skin generic-${project.name} false true device_name Linux N/A kura.primary.network.interface=eth0 cat /proc/cpuinfo | grep Serial | cut -d ' ' -f 2 kura-core setserial, zip, gzip, unzip, procps, usbutils, socat, gawk, sed, inetutils-telnet, polkit | policykit-1 | polkitd, ssh | openssh, openssl, busybox, libpam-modules, python3, openjdk-21-jre-headless | temurin-21-jdk | java-runtime-headless (= 21), dos2unix, libtirpc3, chrony, chronyc | chrony, iputils-ping unset 1024m debian buildNumber generic_debian generic debian ${kura.arch} repo.eclipse.org Eclipse Kura Repository - Releases https://repo.eclipse.org/content/repositories/kura-releases/ repo.eclipse.org Eclipse Kura Repository - Snapshots https://repo.eclipse.org/content/repositories/kura-snapshots/ Eclipse Kura http://www.eclipse.org/kura/ 2017 Kura is a Java/OSGI-based framework for IoT gateways. Kura APIs offer access to the underlying hardware (serial ports, GPS, watchdog, GPIOs, I2C, etc.), management of network configurations, communications with M2M/IoT Integration Platforms, and gateway management. kura-addons Eclipse Kura Addons Maven Repository https://artifactory.dev.everyware.io/artifactory/kura-addons true always eclipse-releases https://repo.eclipse.org/content/groups/releases/ kura-releases Eclipse Kura Repository - Releases https://repo.eclipse.org/content/repositories/kura-releases/ kura-snapshots Eclipse Kura Repository - Snapshots https://repo.eclipse.org/content/repositories/kura-snapshots/ jitpack.io https://jitpack.io org.eclipse.kura target-platform-pde-deps 6.0.0-SNAPSHOT pom javax.usb usb-api org.usb4java usb4java-javax org.usb4java usb4java org.usb4java libusb4java org.eclipse.kura kura-pde-deps 6.0.0-SNAPSHOT pom org.apache.maven.wagon wagon-ssh 1.0-beta-6 org.apache.maven.wagon wagon-webdav-jackrabbit 2.2 org.codehaus.mojo build-helper-maven-plugin 3.6.0 regex-property regex-property release.version ${project.version} -SNAPSHOT false io.github.git-commit-id git-commit-id-maven-plugin 9.0.1 get-the-git-infos revision initialize true false false ^git.commit.id.abbrev$ org.codehaus.mojo build-helper-maven-plugin 1.9 set-deployment-package-version regex-property deployment.package.version ${project.version} -SNAPSHOT .qualifier false maven-antrun-plugin verify-if-snapshot install run true calc-checksums install run false maven-resources-plugin copy-common-resources generate-sources copy-resources ../../../../src/main/resources/filtered true ../../../src/main/resources/filtered true ../../src/main/resources/filtered true ../src/main/resources/filtered true ../../../../src/main/resources/unfiltered false ../../../src/main/resources/unfiltered false ../../src/main/resources/unfiltered false ../src/main/resources/unfiltered false true ${skip.resource.copy} copy-project-resources generate-sources copy-resources src/main/resources/filtered true src/main/resources/unfiltered false true ${project.build.directory} \ maven-dependency-plugin core-launcher generate-sources copy-dependencies ${project.build.directory}/pkg/plugins org.eclipse.osgi, org.eclipse.equinox.launcher core-plugins-1 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/1 asm, org.eclipse.equinox.console, asm-tree, asm-util, log4j2-api-config, asm-analysis, asm-commons core-plugins-1s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/1s org.apache.aries.spifly.dynamic.bundle, log4j-slf4j2-impl, org.eclipse.equinox.common, org.eclipse.equinox.cm, org.eclipse.equinox.event, jcl-over-slf4j, log4j-api, log4j-core, org.eclipse.equinox.metatype, org.eclipse.equinox.util, org.eclipse.equinox.registry, slf4j-api, org.eclipse.equinox.io, jul-to-slf4j, org.apache.felix.scr, org.eclipse.kura.jul.to.slf4j.configuration core-plugins-2 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/2 jakarta.xml.bind-api, jakarta.xml.soap-api, org.osgi.util.function, org.osgi.service.prefs, jakarta.annotation-api, org.osgi.service.event, org.osgi.service.coordinator, org.osgi.service.device, org.osgi.util.measurement, jakarta.xml.ws-api, org.osgi.service.metatype, jakarta.activation-api, org.osgi.service.component, org.osgi.service.log.stream, org.osgi.util.pushstream, org.eclipse.kura.sun.misc, org.osgi.service.wireadmin, org.osgi.util.promise, org.osgi.util.xml, org.osgi.service.upnp, org.osgi.service.provisioning, org.osgi.service.cm, org.osgi.util.position, org.osgi.service.useradmin core-plugins-2s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/2s osgi-resource-locator, org.osgi.service.http.whiteboard, org.osgi.service.servlet, org.eclipse.osgi.util, jaxb-osgi core-plugins-3 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/3 bcutil-jdk18on, jakarta.validation-api, hk2-locator, bcpg-jdk18on, com.codeminders.hidapi.${native.tag}, hk2-utils, org.apache.servicemix.bundles.c3p0, jersey-media-multipart, HikariCP, quartz, jersey-hk2, jersey-common, jersey-server, jakarta.inject-api, bctls-jdk18on, jersey-container-servlet, mimepull, org.eclipse.soda.dk.comm.${native.tag}, jersey-client, hk2-api, javassist, jersey-media-sse, protobuf-java, bcpkix-jdk18on, jersey-entity-filtering, jersey-media-jaxb, commons-csv, gson, aopalliance-repackaged, bcprov-jdk18on, jersey-container-servlet-core, netty-common, netty-codec-http, netty-codec, netty-transport, netty-buffer, netty-transport-classes-epoll, netty-resolver, netty-handler, netty-transport-classes-kqueue, netty-transport-native-epoll, netty-codec-mqtt, netty-transport-native-kqueue, netty-transport-native-unix-common, netty-codec-socks, netty-handler-proxy, failureaccess, guava, jackson-databind, jackson-annotations, jackson-core, geronimo-jms_2.0_spec sources,linux-x86_64,linux-aarch_64,osx-x86_64,osx-aarch_64 core-plugins-3s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/3s org.eclipse.kura.core.crypto, org.eclipse.kura.api, org.eclipse.kura.useradmin.store, org.eclipse.soda.dk.comm, commons-fileupload2-jakarta-servlet5, org.apache.felix.deploymentadmin, org.apache.felix.useradmin, org.apache.felix.dependencymanager, commons-net, h2, commons-fileupload2-core, com.codeminders.hidapi, commons-io, monitoradmin, org.eclipse.kura.xml.marshaller.unmarshaller.provider, org.eclipse.kura.json.marshaller.unmarshaller.provider core-plugins-4 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/4 org.eclipse.kura.core.status, org.eclipse.kura.db.h2db.provider, org.eclipse.kura.linux.clock, org.eclipse.kura.request.handler.jaxrs core-plugins-4s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/4s org.eclipse.kura.driver.helper.provider, org.eclipse.kura.core.certificates, org.eclipse.kura.util, org.eclipse.kura.configuration.change.manager, org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider, org.eclipse.kura.cloudconnection.kapua.mqtt.provider, org.eclipse.kura.log.filesystem.provider, org.eclipse.kura.rest.keystore.provider, org.eclipse.kura.rest.inventory.provider, org.eclipse.kura.rest.configuration.provider, org.eclipse.kura.rest.system.provider, org.eclipse.kura.rest.provider, org.eclipse.kura.rest.security.provider, org.eclipse.kura.rest.identity.provider, org.eclipse.kura.rest.service.listing.provider, org.eclipse.kura.rest.cloudconnection.provider, org.eclipse.kura.core.identity, org.eclipse.kura.core, org.eclipse.kura.misc.cloudcat, org.eclipse.kura.core.keystore, commons-lang3, usb4java-javax, org.usb4java, org.eclipse.kura.core.system, org.eclipse.kura.core.cloud.factory, org.eclipse.kura.cloud.base.provider, org.eclipse.kura.core.configuration, org.eclipse.kura.core.inventory, org.eclipse.kura.core.comm core-plugins-5 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/5 org.apache.felix.gogo.shell, jetty-security, org.apache.felix.http.proxy, org.apache.felix.http.wrappers, jetty-server, jetty-util, jetty-http, org.eclipse.osgitech.rest.sse, org.apache.felix.gogo.command, org.apache.felix.gogo.runtime, jetty-session, jetty-io, org.apache.felix.http.servlet-api core-plugins-5s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/5s org.eclipse.kura.event.publisher, org.eclipse.kura.http.server.manager, org.eclipse.osgitech.rest, jakarta.ws.rs-api, jetty-ee10-servlet, org.apache.felix.http.bridge, org.osgi.service.jakartars, org.eclipse.osgitech.rest.servlet.whiteboard core-plugins-6 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/6 minimal-json, commons-exec linux-plugins-4 generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/4 ${exclude.linux.plugins} org.eclipse.kura.linux.watchdog, org.eclipse.kura.linux.usb, org.eclipse.kura.linux.usb.${native.tag} linux-plugins-4s generate-sources copy-dependencies ${project.build.directory}/pkg/plugins/4s ${exclude.linux.plugins} org.eclipse.kura.container.provider, org.eclipse.kura.container.orchestration.provider org.vafer jdeb ${jdeb-version} deb package jdeb true ${project.build.directory}/${deb.name}_${package.version}-${package.revision}_${deb.architecture}.deb true ${package.snapshot} ${project.build.directory}/deb/control false template ${kura.install.dir} ${kura.install.dir}/${kura.symlink} ${kura.install.dir}/${kura.symlink}/.data perm root root 600 template true ${kura.install.dir}/${kura.symlink}/data ${kura.install.dir}/${kura.symlink}/packages perm root root 600 ${project.build.directory}/pkg/bin/ directory perm ${kura.install.dir}/${kura.symlink}/bin root root 700 ${project.build.directory}/pkg/framework/ directory perm ${kura.install.dir}/${kura.symlink}/framework root root 600 ${project.build.directory}/pkg/packages/ directory perm ${kura.install.dir}/${kura.symlink}/packages root root 600 ${project.build.directory}/pkg/plugins/ directory perm ${kura.install.dir}/${kura.symlink}/plugins root root 600 ${project.build.directory}/pkg/user/ directory true perm ${kura.install.dir}/${kura.symlink}/user root root 600 ${project.build.directory}/pkg/log4j/ directory true perm ${kura.install.dir}/${kura.symlink}/log4j root root 600 ${project.build.directory}/pkg/install/ directory perm ${kura.install.dir}/${kura.symlink}/install root root 600 template true ${kura.install.dir}/${kura.symlink}/data ${kura.install.dir}/${kura.symlink}/packages perm root root 600 org.eclipse.m2e lifecycle-mapping 1.0.0 org.codehaus.mojo properties-maven-plugin [1.2.1,) read-project-properties org.codehaus.mojo buildnumber-maven-plugin [1.0,) create-timestamp org.apache.maven.plugins maven-dependency-plugin [1.0,) copy org.apache.maven.plugins maven-antrun-plugin [1.0,) run org.codehaus.mojo build-helper-maven-plugin [1.9,) regex-property debugBuild !releaseBuild yyyyMMddHHmm git${maven.build.timestamp}.${git.commit.id.abbrev} ${release.version}~${package.snapshot} 1 releaseBuild releaseBuild ${release.version} 1 org.apache.maven.plugins maven-enforcer-plugin 3.5.0 enforce-no-snapshots enforce No snapshots allowed for release builds! true core-dp core-dp ================================================ FILE: kura/distrib/src/main/resources/filtered/pkg/bin/start_kura.sh ================================================ #!/bin/bash # # Copyright (c) 2025, 2026 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # # Kura should be installed to the \${kura.install.dir} directory. export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/opt/jvm/bin:/usr/java/bin:$PATH export MALLOC_ARENA_MAX=1 KURA_RUNNING=$(pgrep -f ".*java.*org\.eclipse\.equinox\..*") if [ -n "$KURA_RUNNING" ] ; then echo "Failed to start Kura. It is already running ..." exit 1 fi DIR=$(cd $(dirname $0)/..; pwd) cd "$DIR" || exit 1 IS_DEBUG_MODE="false" IS_DETACHED_MODE="false" while [[ $# -gt 0 ]]; do key="$1" case $key in -d | --detached) IS_DETACHED_MODE="true" ;; -x | --debug) IS_DEBUG_MODE="true" ;; -h | --help) echo echo "Options:" echo " -d | --detached run Kura in detached mode" echo " -x | --debug run Kura in debug mode" exit 0 ;; *) echo "Unknown option." exit 1 ;; esac shift # past argument or value done # set up the configuration area mkdir -p /tmp/.kura/configuration \${DIR}/bin/gen_config_ini.sh \${DIR}/framework/config.ini \${DIR}/plugins > /tmp/.kura/configuration/config.ini if [[ -n "${KURA_DEBUG_MODE}" && "${KURA_DEBUG_MODE}" == "true" ]]; then IS_DEBUG_MODE="true" fi DEBUG_OPTS="" EQUINOX_DEBUG_OPTS="" if [[ $IS_DEBUG_MODE == "true" ]]; then DEBUG_OPTS="-Xdebug \ -Xrunjdwp:server=y,transport=dt_socket,address=*:8000,suspend=n \ -Xlog:gc=info:file=/var/log/kura-gc.log:time:filecount=10,filesize=10m \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=/var/log/kura-heapdump.hprof \ -XX:ErrorFile=/var/log/kura-error.log" EQUINOX_DEBUG_OPTS="-console 5002 \ -consoleLog" fi KURA_LAUNCH_COMMAND="exec java" if [[ $IS_DETACHED_MODE == "true" ]]; then KURA_LAUNCH_COMMAND="nohup java" fi KURA_CMD="${KURA_LAUNCH_COMMAND} -Xms${kura.mem.size} -Xmx${kura.mem.size} \ $DEBUG_OPTS \ -XX:+IgnoreUnrecognizedVMOptions \ --add-opens java.base/java.lang=ALL-UNNAMED \ --add-opens java.base/java.util=ALL-UNNAMED \ --add-modules=ALL-SYSTEM \ -Dkura.os.version=${kura.os.version} \ -Dkura.arch=${kura.arch} \ -Dtarget.device=${target.device} \ -Declipse.ignoreApp=true \ -Dkura.home=\${DIR} \ -Dkura.configuration=file:\${DIR}/framework/kura.properties \ -Dkura.custom.configuration=file:\${DIR}/user/kura_custom.properties \ -Ddpa.configuration=\${DIR}/packages/dpa.properties \ -Dlog4j.configurationFile=file:\${DIR}/log4j/log4j.xml \ -Dlog4j2.disable.jmx=true \ -Djdk.tls.trustNameService=true \ -Declipse.consoleLog=true \ -jar \${DIR}/plugins/org.eclipse.equinox.launcher-${org.eclipse.equinox.launcher.version}.jar \ -configuration /tmp/.kura/configuration \ $EQUINOX_DEBUG_OPTS" if [[ $IS_DETACHED_MODE == "true" ]]; then eval "$KURA_CMD &" #Save the PID KURA_PID=$! echo "Kura Started (pid=$KURA_PID) ..." echo $KURA_PID > /var/run/kura.pid else eval "$KURA_CMD" fi ================================================ FILE: kura/distrib/src/main/resources/filtered/pkg/framework/kura.properties ================================================ # # Copyright (c) 2023 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # ## ----------------------------------------------------------------------------- ## Kura Properties ## ----------------------------------------------------------------------------- kura.name=Eclipse Kura kura.version=${kura.version} kura.marketplace.compatibility.version=${kura.marketplace.compatibility.version} kura.company=Eclipse kura.platform=kura_platform kura.project=${kura.project} kura.device.name=${device.name} kura.model.id=${device.name} kura.model.name=${device.name} kura.partNumber=${device.name} ${kura.serialNumber} ${kura.serialNumber.provider} kura.bios.version=N/A kura.firmware.version=N/A ${kura.primary.network.interface} # kura.mac.address= Fetch from Java kura.home=${kura.install.dir}/${kura.symlink} kura.framework.config=${kura.install.dir}/${kura.symlink}/framework kura.user.config=${kura.install.dir}/${kura.symlink}/user kura.plugins=${kura.install.dir}/${kura.symlink}/plugins kura.packages=${kura.install.dir}/${kura.symlink}/packages kura.data=${kura.install.dir}/${kura.symlink}/data kura.tmp=/tmp/.kura kura.snapshots=${kura.install.dir}/${kura.symlink}/user/snapshots kura.style.dir=${kura.install.dir}/${kura.symlink}/console/skin kura.have.net.admin=${kura.have.net.admin} kura.net.virtual.devices.config=unmanaged kura.log.download.sources=/var/log kura.log.download.journal.fields=SYSLOG_IDENTIFIER,PRIORITY,MESSAGE,STACKTRACE # os.arch= Fetch from Java # os.name= Fetch from Java # os.version= Fetch from Java os.distribution=${os.distribution} os.distribution.version=${os.distribution.version} # java.version= Fetch from Java # java.vendor= Fetch from Java # java.vm.name= Fetch from Java # java.vm.version= Fetch from Java # java.home= Fetch from Java # file.separator= Fetch from Java kura.command.user=kura kura.legacy.bluetooth.beacon.scan=false kura.legacy.ppp.logging.enabled=true kura.default.log.manager=filesystem-kura-log ## ----------------------------------------------------------------------------- ## Remote Configuration Properties ## ----------------------------------------------------------------------------- console.device.management.service.ignore=org.eclipse.kura.net.admin.NetworkConfigurationService,org.eclipse.kura.net.admin.FirewallConfigurationService ## ----------------------------------------------------------------------------- ## File upload settings ## ----------------------------------------------------------------------------- # default 10240 file.upload.in.memory.size.threshold=10240 # -1: unlimited (default) file.upload.size.max=-1 file.command.zip.max.size=100 file.command.zip.max.number=1024 ## ----------------------------------------------------------------------------- ## Deployment Agent settings ## ----------------------------------------------------------------------------- # see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html dpa.connection.timeout = 60000 dpa.read.timeout = 60000 ## ----------------------------------------------------------------------------- ## Cloud Connection Status settings ## ----------------------------------------------------------------------------- #1. Cloud Connection Status on system log #The Cloud Connection Status will be indicated in the log files, and nowere else ccs.status.notification.url=ccs:log #2. Cloud Connection Status on LED #The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs #The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService. # Syntax for using GPIO terminal index: #ccs.status.notification.url=ccs:led:16 #ccs.status.notification.url=ccs:led:terminal:16 # Syntax for using GPIO name: #ccs.status.notification.url=ccs:led:name:LED_1 #3. Cloud Connection Status disabled #Disables the Cloud Connection Status service #ccs.status.notification.url=ccs:none version=${kura.version} build.version=${buildNumber} build.number=${build.name}-${buildNumber} ================================================ FILE: kura/distrib/src/main/resources/filtered/pkg/install/kura.service ================================================ [Unit] Description=Kura Wants=dbus.service,docker.service After=dbus.service,docker.service [Service] User=kurad Group=kurad Type=forking ExecStart=/bin/bash ${kura.install.dir}/kura/bin/start_kura.sh --detached ExecStopPost=/bin/bash -c 'if [ -f /tmp/watchdog ]; then echo w > `cat /tmp/watchdog`; fi' PIDFile=/var/run/kura.pid Restart=on-failure RestartSec=5 SuccessExitStatus=143 KillMode=process AmbientCapabilities=cap_dac_override cap_dac_read_search cap_net_bind_service cap_sys_boot cap_kill cap_sys_module cap_sys_time cap_sys_tty_config cap_syslog [Install] WantedBy=multi-user.target ================================================ FILE: kura/distrib/src/main/resources/filtered/pkg/install/kura_install.sh ================================================ #!/bin/sh # # Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # backup_files() { SUFFIX="\${1}" shift for file in "\${@}" do if [ -f "\${file}" ] then mv "\${file}" "\${file}.\${SUFFIX}" fi done } INSTALL_DIR=${kura.install.dir} # set up kura init cp \${INSTALL_DIR}/kura/install/kura.service /lib/systemd/system/kura.service systemctl daemon-reload systemctl enable kura chmod +x \${INSTALL_DIR}/kura/bin/*.sh # setup snapshot_0 recovery folder if [ ! -d \${INSTALL_DIR}/kura/.data ]; then mkdir \${INSTALL_DIR}/kura/.data fi mkdir -p \${INSTALL_DIR}/kura/data # manage running services systemctl daemon-reload systemctl stop systemd-timesyncd systemctl disable systemd-timesyncd systemctl stop chrony systemctl disable chrony # set up users and grant permissions cp \${INSTALL_DIR}/kura/install/manage_kura_users.sh \${INSTALL_DIR}/kura/.data/manage_kura_users.sh chmod 700 \${INSTALL_DIR}/kura/.data/manage_kura_users.sh \${INSTALL_DIR}/kura/.data/manage_kura_users.sh -i -nn bash "\${INSTALL_DIR}/kura/install/customize-installation.sh" # copy snapshot_0.xml cp \${INSTALL_DIR}/kura/user/snapshots/snapshot_0.xml \${INSTALL_DIR}/kura/.data/snapshot_0.xml # copy network_tools.py cp \${INSTALL_DIR}/kura/install/network_tools.py \${INSTALL_DIR}/kura/.data/network_tools.py # disable NTP service if command -v timedatectl > /dev/null ; then timedatectl set-ntp false fi # set up systemd-tmpfiles cp \${INSTALL_DIR}/kura/install/kura-tmpfiles.conf /etc/tmpfiles.d/kura.conf # set up kura files permissions chmod 700 \${INSTALL_DIR}/kura/bin/*.sh chown -R kurad:kurad /opt/eclipse chmod -R go-rwx /opt/eclipse chmod a+rx /opt/eclipse find /opt/eclipse/kura -type d -exec chmod u+x "{}" \; keytool -genkey -alias localhost -keyalg RSA -keysize 2048 -keystore /opt/eclipse/kura/user/security/httpskeystore.ks -deststoretype pkcs12 -dname "CN=Kura, OU=Kura, O=Eclipse Foundation, L=Ottawa, S=Ontario, C=CA" -ext ku=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign -ext eku=serverAuth,clientAuth,codeSigning,timeStamping -validity 1000 -storepass changeit -keypass changeit ================================================ FILE: kura/distrib/src/main/resources/unfiltered/deb/control/control ================================================ # # Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Package: [[deb.name]] Version: [[version]]-[[package.revision]] Section: admin Priority: optional Provides: [[deb.provides]] Depends: [[deb.dependencies]] Recommends: [[deb.recommendations]] Architecture: [[deb.architecture]] Maintainer: Eclipse Kura Developers Homepage: https://eclipse-kura.github.io/kura/ Description: Open-source IoT edge framework based on Java/OSGi Kura is an inclusive software framework that puts a layer between the operating system and the customer application, with industry standard interfaces that shorten custom development time, simplified coding and software that can be easily ported from one hardware platform to another. ================================================ FILE: kura/distrib/src/main/resources/unfiltered/deb/control/postinst ================================================ #!/bin/bash # # Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # INSTALL_DIR=/opt/eclipse TIMESTAMP=`date +%Y%m%d%H%M%S` LOG=/tmp/kura_install_${TIMESTAMP}.log WD_TMP_FILE=/tmp/watchdog REFRESH_TIME=5 TIMEOUT_TIME=300 ############################################## # UTILITY FUNCTIONS ############################################## # Run postInstall function and start watchdog if needed function runPostInstall { if [ -f "${WD_TMP_FILE}" ]; then WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}` echo "Got watchdog ${WATCHDOG_DEVICE}" >> $LOG 2>&1 postInstall & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do echo w > ${WATCHDOG_DEVICE} DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done stopWatchdog else postInstall & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done fi } # Deactivate watchdog device if possible function stopWatchdog { if [ -n "${WATCHDOG_DEVICE}" ]; then echo V > ${WATCHDOG_DEVICE} fi } # Post-install script function postInstall { #install KURA files sh ${INSTALL_DIR}/kura/install/kura_install.sh >> ${LOG} 2>&1 #clean up rm -rf ${INSTALL_DIR}/kura/install >> ${LOG} 2>&1 #move the log file mkdir -p ${INSTALL_DIR}/kura/log mv ${LOG} ${INSTALL_DIR}/kura/log/ #flush all cached filesystem to disk sync echo "" echo "Finished. KURA has been installed to ${INSTALL_DIR}/kura and will start automatically after a reboot" echo "" echo "****************************************************************" echo "WARNING: Set the crypto service encryption key as explained in Eclipse Kura" echo "documentation before rebooting to have snapshot encryption enabled." echo "****************************************************************" } ############################################## # END UTILITY FUNCTIONS ############################################## ############################################## # POST INSTALL SCRIPT ############################################## # Handle abort-upgrade case if [ "$1" = "abort-upgrade" ]; then echo "postinst called with abort-upgrade: nothing to do." exit 0 fi runPostInstall exit 0 ############################################# # END POST INSTALL SCRIPT ############################################## ================================================ FILE: kura/distrib/src/main/resources/unfiltered/deb/control/preinst ================================================ #!/bin/bash # # Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # INSTALL_DIR=/opt/eclipse WD_TMP_FILE=/tmp/watchdog REFRESH_TIME=5 TIMEOUT_TIME=300 SYSTEMD_WATCHDOG_CONFIG="[Manager] RuntimeWatchdogSec=0 RebootWatchdogSec=0 KExecWatchdogSec=0 " ############################################## # UTILITY FUNCTIONS ############################################## # Run preInstall function and start watchdog if needed function runPreInstall { if [ -f "${WD_TMP_FILE}" ]; then WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}` preInstall & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do echo w > ${WATCHDOG_DEVICE} DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done stopWatchdog else preInstall & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done fi } # Deactivate watchdog device if possible function stopWatchdog { if [ -n "${WATCHDOG_DEVICE}" ]; then echo V > ${WATCHDOG_DEVICE} fi } function disable_systemd_watchdog() { # disable systemd watchdog # https://manpages.debian.org/testing/systemd/systemd-system.conf.5.en.html # # Order of application of conf files: # 1. /usr/lib/systemd/system.conf.d/ # 2. /usr/local/lib/systemd/system.conf.d/ # 3. /etc/systemd/system.conf.d/ # docs suggest to use 10-40 priority for drop-ins in /usr/, and 50-90 for /etc/ # we use zz since some OSs do not respect that convention (raspbian, ubuntu jammy) # path="" if [ -d /usr/lib/systemd/system.conf.d/ ]; then path="/usr/lib/systemd/system.conf.d" elif [ -d /usr/local/lib/systemd/system.conf.d/ ]; then path="/usr/local/lib/systemd/system.conf.d" elif [ -d /etc/systemd/system.conf.d/ ]; then path="/etc/systemd/system.conf.d" fi if [ ! -z "${path}" ]; then echo "Installing $path/zz-kura-disable-watchdog.conf" echo -e "${SYSTEMD_WATCHDOG_CONFIG}" > ${path}/zz-kura-disable-watchdog.conf chmod 644 ${path}/zz-kura-disable-watchdog.conf systemctl daemon-reload else echo "No systemd drop-in directory found, watchdog not disabled" fi } # Pre-install script function preInstall { #clean up old installation if present rm -fr /opt/eclipse/kura* >> /tmp/kura_install.log 2>&1 rm -fr ${INSTALL_DIR}/kura* >> /tmp/kura_install.log 2>&1 rm -fr /tmp/.kura/ >> /tmp/kura_install.log 2>&1 rm /var/log/kura.log >> /tmp/kura_install.log 2>&1 rm -f kura-*.zip >> /tmp/kura_install.log 2>&1 rm -f kura_*.zip >> /tmp/kura_install.log 2>&1 echo "" } ############################################## # END UTILITY FUNCTIONS ############################################## ############################################## # PRE-INSTALL SCRIPT ############################################## PIDS=`pgrep java` echo "" echo "Installing Kura..." echo "Installing Kura..." > /tmp/kura_install.log 2>&1 #Kill JVM and monit for installation if [ -f "/var/run/kura.pid" ] ; then KURA_PID=`cat /var/run/kura.pid` for pid in "${PIDS[@]}" do if [ "$KURA_PID" == "$pid" ] ; then `kill $pid` >> /tmp/kura_install.log 2>&1 fi done fi disable_systemd_watchdog runPreInstall ############################################## # END PRE-INSTALL SCRIPT ############################################## ================================================ FILE: kura/distrib/src/main/resources/unfiltered/deb/control/prerm ================================================ #!/bin/bash # # Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # INSTALL_DIR=/opt/eclipse WD_TMP_FILE=/tmp/watchdog REFRESH_TIME=5 TIMEOUT_TIME=300 TIMESTAMP=$(date +%Y%m%d%H%M) LOG=/tmp/kura_uninstall_${TIMESTAMP}.log ############################################## # UTILITY FUNCTIONS ############################################## # Run preRemove function and start watchdog if needed function runPreRemove { if [ -f "${WD_TMP_FILE}" ]; then WATCHDOG_DEVICE=`cat ${WD_TMP_FILE}` preRemove & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do echo w > ${WATCHDOG_DEVICE} DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done stopWatchdog else preRemove & PID=$! START=$(date +%s) while [ -d "/proc/$PID" ]; do DELTA=$(($(date +%s) - $START)) if [ "$DELTA" -ge "$TIMEOUT_TIME" ]; then echo "The installation process is not responding. It'll be stopped." kill -9 $PID >> /dev/null 2>&1 fi sleep $REFRESH_TIME done fi } # Deactivate watchdog device if possible function stopWatchdog { if [ -n "${WATCHDOG_DEVICE}" ]; then echo V > ${WATCHDOG_DEVICE} fi } function restore_systemd_watchdog() { file_to_restore="" if [ -f /usr/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then file_to_restore="/usr/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf" fi if [ -f /usr/local/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then file_to_restore="/usr/local/lib/systemd/system.conf.d/zz-kura-disable-watchdog.conf" fi if [ -f /etc/systemd/system.conf.d/zz-kura-disable-watchdog.conf ]; then file_to_restore="/etc/systemd/system.conf.d/zz-kura-disable-watchdog.conf" fi if [ ! -z "${file_to_restore}" ]; then echo "Restoring systemd watchdog configuration: removing ${file_to_restore}" rm "${file_to_restore}" systemctl daemon-reload fi } function restore_backup_files { SUFFIX="${1}" shift for file in "${@}" do if [ -f "${file}" ] && expr "${file}" : ".*[.]${SUFFIX}$" > /dev/null; then mv "${file}" "${file%."${SUFFIX}"}" fi done } # Pre-remove script function preRemove { #Remove INIT scripts if [ -f /etc/init.d/kura ] ; then rm /etc/init.d/kura update-rc.d kura remove fi if [ -f /lib/systemd/system/kura.service ] ; then systemctl disable kura rm /lib/systemd/system/kura.service fi rm -f /var/log/kura*.log rm -f /var/log/kura*.gz rm -rf /tmp/.kura rm -rf /tmp/kura if [ -d "${INSTALL_DIR}/kura" ] ; then ${INSTALL_DIR}/kura/.data/manage_kura_users.sh -u PARENT=`readlink -f ${INSTALL_DIR}/kura` rm -rf ${INSTALL_DIR}/kura rm -rf $PARENT fi restore_systemd_watchdog } ############################################## # END UTILITY FUNCTIONS ############################################## ############################################## # PRE-REMOVE SCRIPT ############################################## # Fail if the first argument is 'upgrade' or 'failed-upgrade' if [ "$1" == "upgrade" ]; then echo "" echo "#####################################################################" echo "# #" echo "# ERROR: KURA upgrade is NOT supported! #" echo "# Please uninstall the existing version before upgrading. #" echo "# #" echo "# To prevent accidental upgrades, you can hold this package with: #" echo "# sudo apt-mark hold kura #" echo "# #" echo "#####################################################################" echo "" exit 1 fi if [ "$1" == "failed-upgrade" ]; then echo "This package cannot be upgraded. Please uninstall the existing version before installing a new one." exit 1 fi echo "" echo "Uninstalling KURA..." PIDS=`pgrep java` #Kill JVM and monit for installation if [ -f "/var/run/kura.pid" ] ; then KURA_PID=`cat /var/run/kura.pid` for pid in "${PIDS[@]}" do if [ "$KURA_PID" == "$pid" ] ; then `kill $pid` >> "$LOG" 2>&1 fi done fi runPreRemove >> "$LOG" 2>&1 mkdir -p /opt/eclipse/kura/log/ mv "$LOG" /opt/eclipse/kura/log/ echo "" echo "Uninstalling KURA... Done!" ############################################## # END PRE-REMOVE SCRIPT ############################################## ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/bin/gen_config_ini.sh ================================================ #!/bin/sh TEMPLATE=$1 ROOT=$2 usage() { >&2 echo "Usage: gen_config_ini.sh " } abspath() { cd "${1}" || exit 1 RESULT="${PWD}" cd "${OLDPWD}" || exit 1 echo "${RESULT}" } if ! [ -e "${TEMPLATE}" ] then >&2 echo "config.ini template not found" usage exit 1 fi if ! [ -d "${ROOT}" ] then >&2 echo "plugin root directory not found" usage exit 1 fi ROOT=$(abspath "${ROOT}") OSGI_BUNDLES= for DIR_PATH in "${ROOT}"/* do DIR_NAME=$(basename -- "${DIR_PATH}") if [ "${#DIR_NAME}" = 0 ] || [ "${#DIR_NAME}" -gt 2 ] || ! [ -d "${DIR_PATH}" ] then continue fi if ! expr "${DIR_NAME}" : '[0-9]\{1,\}s\{0,1\}$' > /dev/null then continue fi START_LEVEL="${DIR_NAME%s}" if [ "${#DIR_NAME}" = "${#START_LEVEL}" ] then START= else START="\:start" fi for JAR in "${DIR_PATH}"/*.jar do if [ -n "${OSGI_BUNDLES}" ] then OSGI_BUNDLES="${OSGI_BUNDLES}," fi OSGI_BUNDLES="${OSGI_BUNDLES}reference\:file\:${JAR}@${START_LEVEL}${START}" done done cat "${TEMPLATE}" echo echo "osgi.bundles=${OSGI_BUNDLES}" ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/framework/config.ini ================================================ #Configuration File osgi.framework=file\:plugins/org.eclipse.osgi-3.21.0.jar equinox.use.ds=true osgi.nl=en_us osgi.clean=true osgi.noShutdown=true osgi.bundles.defaultStartLevel=5 osgi.framework.extensions= osgi.instance.area=/tmp/.kura/data org.osgi.service.http.port=80 osgi.configuration.cascaded=false eclipse.ignoreApp=true iagent.controller=false ds.lock.timeout.milliseconds=60000 ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/customize-installation.sh ================================================ #!/bin/bash # # Copyright (c) 2023, 2026 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # setup_libudev() { # create soft link for libudev.so.0 to make it retrocompatible # https://unix.stackexchange.com/questions/156776/arch-ubuntu-so-whats-the-deal-with-libudev-so-0 if [ ! -f /lib/libudev.so.0 ] && [ -f /lib/libudev.so.1 ]; then ln -sf /lib/libudev.so.1 /lib/libudev.so.0 fi if uname -m | grep -q arm ; then destination="/usr/lib/arm-linux-gnueabihf/libudev.so.1" link_name="/usr/lib/arm-linux-gnueabihf/libudev.so.0" fi if uname -m | grep -q aarch ; then destination="/usr/lib/aarch64-linux-gnu/libudev.so.1" link_name="/usr/lib/aarch64-linux-gnu/libudev.so.0" fi if uname -m | grep -q x86_64 ; then destination="/usr/lib/x86_64-linux-gnu/libudev.so.1" link_name="/usr/lib/x86_64-linux-gnu/libudev.so.0" fi if [ -f "${destination}" ] && [ ! -f "${link_name}" ]; then echo "Setting up symlink ${link_name} -> ${destination}" ln -sf "${destination}" "${link_name}" fi } install_snapshot() { if [ ! -d "/opt/eclipse/kura/user/snapshots/" ]; then mkdir /opt/eclipse/kura/user/snapshots/ fi mv "/opt/eclipse/kura/install/snapshot_0.xml" "/opt/eclipse/kura/user/snapshots/snapshot_0.xml" } customize_kura_properties() { local BOARD=$1 KURA_PLATFORM=$( uname -m ) sed -i "s/kura_platform/${KURA_PLATFORM}/g" "/opt/eclipse/kura/framework/kura.properties" python3 "/opt/eclipse/kura/install/customize_kura_properties.py" "${BOARD}" } customize_ram() { local BOARD=$1 if [ ${BOARD} = "generic-device" ]; then # dynamic RAM assignment RAM_KB=$(grep MemTotal /proc/meminfo | awk '{print $2}') RAM_MB=$(expr $RAM_KB / 1024) RAM_MB_FOR_KURA=$(expr $RAM_MB / 4) if [ "$RAM_MB" -lt 1024 ]; then RAM_MB_FOR_KURA="256" fi echo "Setting kura RAM to ${RAM_MB_FOR_KURA}" RAM_REPLACEMENT_STRING="-Xms${RAM_MB_FOR_KURA}m -Xmx${RAM_MB_FOR_KURA}m" echo "Updating RAM values for start_kura.sh" sed -i "s/-Xms[0-9]*m -Xmx[0-9]*m/$RAM_REPLACEMENT_STRING/g" "/opt/eclipse/kura/bin/start_kura.sh" fi } setup_libudev BOARD="generic-device" if uname -a | grep -q 'raspberry' > /dev/null 2>&1 then BOARD="raspberry" echo "Customizing installation for Raspberry PI" fi install_snapshot customize_kura_properties "${BOARD}" customize_ram "${BOARD}" ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/customize_kura_properties.py ================================================ #!/usr/bin/env python3 # # Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # import sys import logging import argparse sys.path.append("/opt/eclipse/kura/.data") from network_tools import get_eth_wlan_interfaces_names def main(): logging.basicConfig( format='[customize_kura_properties.py] %(asctime)s %(levelname)s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S', handlers=[ logging.StreamHandler() ] ) parser = argparse.ArgumentParser(description="Customize kura properties file", usage='%(prog)s device_name') parser.add_argument('device_name', help='The name of the device') args = parser.parse_args() KURA_PROPERTIES_FILENAME = "/opt/eclipse/kura/framework/kura.properties" (eth_names, wlan_names) = get_eth_wlan_interfaces_names() if len(eth_names) == 0: logging.info("ERROR: no ethernet interface found") exit(1) logging.info("%s : starting editing", KURA_PROPERTIES_FILENAME) with open(KURA_PROPERTIES_FILENAME, 'r', encoding='utf-8') as kura_properties: kura_properties_content = kura_properties.read() kura_properties_content = kura_properties_content.replace('device_name', args.device_name) kura_properties_content = kura_properties_content.replace('eth0', eth_names[0]) with open(KURA_PROPERTIES_FILENAME, 'w', encoding='utf-8') as kura_properties: kura_properties.write(kura_properties_content) logging.info("%s : successfully edited", KURA_PROPERTIES_FILENAME) if __name__ == "__main__": main() ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/kura-tmpfiles.conf ================================================ # Kura specific file. Do not edit! x /tmp/.kura x /tmp/kura ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/manage_kura_users.sh ================================================ #!/bin/bash # # Copyright (c) 2020, 2024 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # function create_users { # create kura user without home directory useradd -M kura # disable login for kura user passwd -l kura # create kurad system user without home directory useradd -r -M kurad # disable login for kurad user KURAD_USER_ENTRY=$(cat /etc/passwd | grep kurad:) sed -i "s@${KURAD_USER_ENTRY}@${KURAD_USER_ENTRY%:*}:/sbin/nologin@" /etc/passwd passwd -l kurad # add kurad to dialout group (for managing serial ports) gpasswd -a kurad dialout # get polkit package version POLKIT=$(apt list --installed | grep libpolkit) IFS=" " POLKIT_ARRAY=($POLKIT) POLKIT_VERSION=${POLKIT_ARRAY[1]} # add polkit policy if [[ ${POLKIT_VERSION} < 0.106 ]]; then if [ ! -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla ]; then echo "[No password prompt for kurad user] Identity=unix-user:kurad Action=org.freedesktop.systemd1.* ResultInactive=no ResultActive=no ResultAny=yes" >/etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla fi if [[ $NN == "NO" ]]; then if [ ! -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla ]; then echo "[No password prompt for kurad user when using NetworkManager] Identity=unix-user:kurad Action=org.freedesktop.NetworkManager.* ResultInactive=no ResultActive=no ResultAny=yes" >/etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla fi if [ ! -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla ]; then echo "[No password prompt for kurad user when using ModemManager] Identity=unix-user:kurad Action=org.freedesktop.ModemManager1.* ResultInactive=no ResultActive=no ResultAny=yes" >/etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla fi if [ ! -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla ]; then echo "[No password prompt for kurad user when using Wpa Supplicant] Identity=unix-user:kurad Action=fi.w1.wpa_supplicant1.* ResultInactive=no ResultActive=no ResultAny=yes" >/etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla fi fi else if [[ $NN == "NO" ]]; then if [ ! -f /usr/share/polkit-1/rules.d/kura.rules ]; then echo "polkit.addRule(function(action, subject) { if (action.id == \"org.freedesktop.systemd1.manage-units\" && subject.user == \"kurad\" && (action.lookup(\"unit\") == \"named.service\" || action.lookup(\"unit\") == \"chrony.service\" || action.lookup(\"unit\") == \"chronyd.service\" )) { return polkit.Result.YES; } if (action.id == \"org.freedesktop.systemd1.manage-unit-files\" && subject.user == \"kurad\") { return polkit.Result.YES; } if ((action.id == \"org.freedesktop.login1.reboot-multiple-sessions\" || action.id == \"org.freedesktop.login1.suspend-multiple-sessions\" || action.id == \"org.freedesktop.login1.power-off-multiple-sessions\") && subject.user == \"kurad\") { return polkit.Result.YES; } });" >/usr/share/polkit-1/rules.d/kura.rules fi if [ ! -f /usr/share/polkit-1/rules.d/kura-nm.rules ]; then echo "polkit.addRule(function(action, subject) { if ((action.id.indexOf(\"org.freedesktop.NetworkManager.\") == 0 || action.id.indexOf(\"org.freedesktop.ModemManager1.\") == 0 || action.id.indexOf(\"fi.w1.wpa_supplicant1.\") == 0) && subject.user == \"kurad\") { return polkit.Result.YES; } });" >/usr/share/polkit-1/rules.d/kura-nm.rules fi else echo "polkit.addRule(function(action, subject) { if (action.id == \"org.freedesktop.systemd1.manage-units\" && subject.user == \"kurad\" && (action.lookup(\"unit\") == \"chrony.service\" || action.lookup(\"unit\") == \"chronyd.service\" )) { return polkit.Result.YES; } if (action.id == \"org.freedesktop.systemd1.manage-unit-files\" && subject.user == \"kurad\") { return polkit.Result.YES; } if ((action.id == \"org.freedesktop.login1.reboot-multiple-sessions\" || action.id == \"org.freedesktop.login1.suspend-multiple-sessions\" || action.id == \"org.freedesktop.login1.power-off-multiple-sessions\") && subject.user == \"kurad\") { return polkit.Result.YES; } });" >/usr/share/polkit-1/rules.d/kura.rules fi fi # modify pam policy if [ -f /etc/pam.d/su ]; then sed -i '/^auth sufficient pam_rootok.so/a auth [success=ignore default=1] pam_succeed_if.so user = kura\nauth sufficient pam_succeed_if.so use_uid user = kurad' /etc/pam.d/su fi # grant kurad user the privileges to manage wpa supplicant via dbus if ! grep -lR kurad /etc/dbus-1/system.d/wpa_supplicant.conf && [ $NN == "NO" ]; then cp /etc/dbus-1/system.d/wpa_supplicant.conf /etc/dbus-1/system.d/wpa_supplicant.conf.save awk 'done != 1 && /^<\/busconfig>/ { print " " print " " print " " print " " print " " print " \n" done = 1 } 1' /etc/dbus-1/system.d/wpa_supplicant.conf >tempfile && mv tempfile /etc/dbus-1/system.d/wpa_supplicant.conf fi # Change kura folder ownership and permission chown -R kurad:kurad /opt/eclipse chmod -R +X /opt/eclipse } function delete_users { # delete kura user userdel kura # we cannot delete kurad system user because there should be several process owned by this user, # so only try to remove it from sudoers. if [ -f /etc/sudoers.d/kurad ]; then rm -f /etc/sudoers.d/kurad fi # remove kurad from dialout group gpasswd -d kurad dialout # remove polkit policy if [ -f /usr/share/polkit-1/rules.d/kura.rules ]; then rm -f /usr/share/polkit-1/rules.d/kura.rules fi if [ -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla ]; then rm -f /etc/polkit-1/localauthority/50-local.d/51-org.freedesktop.systemd1.pkla fi if [ -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla ]; then rm -f /etc/polkit-1/localauthority/50-local.d/52-org.freedesktop.networkmanager.pkla fi if [ -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla ]; then rm -f /etc/polkit-1/localauthority/50-local.d/53-org.freedesktop.modemmanager.pkla fi if [ -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla ]; then rm -f /etc/polkit-1/localauthority/50-local.d/54-fi.w1.wpa_supplicant1.pkla fi # recover pam policy if [ -f /etc/pam.d/su ]; then sed -i '/^auth sufficient pam_rootok.so/ {n;d}' /etc/pam.d/su sed -i '/^auth sufficient pam_rootok.so/ {n;d}' /etc/pam.d/su fi # recover old configs mv /etc/dbus-1/system.d/wpa_supplicant.conf.save /etc/dbus-1/system.d/wpa_supplicant.conf } INSTALL=YES NN=NO while [[ $# > 0 ]]; do key="$1" case $key in -i | --install) INSTALL=YES ;; -u | --uninstall) INSTALL=NO ;; -nn) NN=YES ;; -h | --help) echo echo "Options:" echo " -i | --install create kura default users" echo " -u | --uninstall delete kura default users" echo " -nn set kura no network version" echo "Default: --install" exit 0 ;; *) echo "Unknown option." exit 1 ;; esac shift # past argument or value done if [[ $INSTALL == "YES" ]]; then create_users else delete_users fi ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/network_tools.py ================================================ #!/usr/bin/env python3 # # Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # import sys import logging import os def get_interface_names(): if not os.path.exists("/sys/class/net"): logging.error("'/sys/class/net' does not exists, unable to read interface names. Exiting.") sys.exit(1) return os.listdir("/sys/class/net") def get_eth_wlan_interfaces_names(): """Reads the network interface names present on the device. It is assumed that at least one ethernet interface is present. Requirements: "/sys/class/net" directory must exist Returns: tuple of lists (eth_names, wlan_names) where: 'eth_names' are the found ethernet interface names sorted by name; 'wlan_names' are the found wireless interface names sorted by name, might be an empty list. """ ethernet_interface_names = list() wireless_interface_names = list() interface_names = get_interface_names() for ifname in interface_names: if ifname.startswith("en") or ifname.startswith("et"): ethernet_interface_names.append(ifname) if ifname.startswith("wl"): wireless_interface_names.append(ifname) ethernet_interface_names.sort() wireless_interface_names.sort() if len(ethernet_interface_names) < 1: logging.error("No ethernet interfaces found, exiting.") sys.exit(1) logging.info("Found ethernet interfaces: %s", ethernet_interface_names) logging.info("Found wireless interfaces: %s", wireless_interface_names) return (ethernet_interface_names, wireless_interface_names) ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/install/snapshot_0.xml ================================================ false org.eclipse.kura.watchdog.WatchdogService 10000 true 123 3600 java-ntp true 10000 0.pool.ntp.org org.eclipse.kura.clock.ClockService SA 10 jdbc:h2:mem:kuradb org.eclipse.kura.core.db.H2DbService 900 org.eclipse.kura.db.H2DbService memory true false 4 org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport 20 org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport mqtt://broker-url:1883/ 30 account-name $EDC/#account-name/#client-id/MQTT/LWT 0 use-ssl-service-config org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory username 60 0 true 9 org.eclipse.kura.data.DataService 10 10 org.eclipse.kura.data.DataService 900 false SECONDS 1 org.eclipse.kura.db.H2DbService (kura.service.pid=org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport) 60 false 1 org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory true 1000 $EDC Unknown Generic Device device-name kura-protobuf org.eclipse.kura.cloud.CloudService org.eclipse.kura.cloud.CloudService true false true (kura.service.pid=org.eclipse.kura.data.DataService) org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory TLSv1.2 true (kura.service.pid=SSLKeystore) org.eclipse.kura.ssl.SslManagerService 100 443 4443 (kura.service.pid=HttpsKeystore) org.eclipse.kura.http.server.manager.HttpService org.eclipse.kura.http.server.manager.HttpService [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="},"properties":{"kura.need.password.change":"true"}}] [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin"},{"name":"kura.permission.kura.device"},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin"},{"name":"kura.permission.kura.packages.admin"},{"name":"kura.permission.kura.wires.admin"},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.deploy"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.configuration"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.security"},{"name":"kura.permission.rest.system"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] /opt/eclipse/kura/user/security/httpskeystore.ks Y2hhbmdlaXQ= true org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl HttpsKeystore /opt/eclipse/kura/user/security/cacerts.ks Y2hhbmdlaXQ= true org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl SSLKeystore /var/log/kura.log org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider filesystem-kura-log org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider-1636726365743-7 /var/log/kura-audit.log org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider filesystem-kura-audit-log org.eclipse.kura.log.filesystem.provider.FilesystemLogProvider-1636726365743-8 false false org.eclipse.kura.internal.rest.provider.RestService org.eclipse.kura.internal.rest.provider.RestService ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/log4j/log4j.xml ================================================ /var/log kura %d{ISO8601} [%t] %-5p %c{1.} - %m%n%throwable{full} ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/packages/.gitkeep ================================================ ================================================ FILE: kura/distrib/src/main/resources/unfiltered/pkg/user/kura_custom.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # # Do not edit the kura.properties file directly, as any changes there may be # lost in subsequent Kura upgrades. Instead, place those changes in this # file to override the value in kura.properties, and they will be carried # across any upgrades. ## ----------------------------------------------------------------------------- ## Kura Custom Properties ## ----------------------------------------------------------------------------- ================================================ FILE: kura/distrib/x86_64-core/pom.xml ================================================ 4.0.0 distrib org.eclipse.kura 6.0.0-SNAPSHOT .. x86_64-core pom ../ x86_64 ${kura.arch} ${kura.arch} kura-core amd64 false maven-dependency-plugin maven-resources-plugin org.vafer jdeb ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator Bundle-SymbolicName: org.eclipse.kura.emulator;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.apache.commons.io;version="2.4.0", org.apache.commons.lang3;version="3.4.0", org.osgi.framework;version="1.7.0", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.7.25" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/OSGI-INF/emulator.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator/build.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ${project.basedir}/../../test/org.eclipse.kura.emulator.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/src/main/java/org/eclipse/kura/emulator/Emulator.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.net.URL; import java.nio.charset.StandardCharsets; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomStringUtils; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Emulator { private static final Logger logger = LoggerFactory.getLogger(Emulator.class); private static final String KURA_SNAPSHOTS_PATH = "kura.snapshots"; private static final String EMULATOR = "emulator"; private static final String KURA_MODE = "org.eclipse.kura.mode"; private static final String SNAPSHOT_0_NAME = "snapshot_0.xml"; private static final String CLIENT_ID_PLACEHOLDER = "{{client-id-placeholder}}"; private ComponentContext componentContext; protected void activate(ComponentContext componentContext) { this.componentContext = componentContext; try { String mode = System.getProperty(KURA_MODE); if (EMULATOR.equals(mode)) { logger.info("Framework is running in emulation mode"); final String snapshotFolderPath = System.getProperty(KURA_SNAPSHOTS_PATH); if (snapshotFolderPath == null || snapshotFolderPath.isEmpty()) { throw new IllegalStateException("System property 'kura.snapshots' is not set"); } final File snapshotFolder = new File(snapshotFolderPath); if (!snapshotFolder.exists() || snapshotFolder.list().length == 0) { snapshotFolder.mkdirs(); copySnapshot(snapshotFolderPath); } } else { logger.info("Framework is not running in emulation mode"); } } catch (Exception e) { logger.info("Framework is not running in emulation mode or initialization failed!: {}", e.getMessage()); } } protected void deactivate(ComponentContext componentContext) { this.componentContext = null; } private void copySnapshot(String snapshotFolderPath) throws IOException { URL internalSnapshotURL = this.componentContext.getBundleContext().getBundle().getResource(SNAPSHOT_0_NAME); try (InputStream fileInput = internalSnapshotURL.openStream(); OutputStream fileOutput = new FileOutputStream(snapshotFolderPath + File.separator + SNAPSHOT_0_NAME)) { String generatedClientId = generateRandomClientId(); String newSnapshot0Content = IOUtils.toString(fileInput, StandardCharsets.UTF_8) .replace(CLIENT_ID_PLACEHOLDER, generatedClientId); logger.info("generated new client-id: {}", generatedClientId); IOUtils.copy(new StringReader(newSnapshot0Content), fileOutput); } } private String generateRandomClientId() { return "kura-emulator-" + RandomStringUtils.randomNumeric(6); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/src/main/resources/kura.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # ## ----------------------------------------------------------------------------- ## Kura Properties ## ----------------------------------------------------------------------------- kura.name=Kura kura.version=kura_emulator kura.marketplace.compatibility.version= kura.company=Eclipse kura.project=Dev kura.platform=DevPlatform kura.device.name=DevEmulator kura.model.id=DevModelId kura.model.name=DevModelName kura.partNumber=DevPartNumber kura.serialNumber=DevSerialNumber kura.bios.version=DevBiosVersion kura.firmware.version=DevFirmwareVersion # Use this in Linux Emulator if your system support Predictable Network Interface Names # kura.primary.network.interface=eth0 # kura.mac.address= Fetch from Java kura.home=/tmp/kura kura.framework.config=/tmp/kura/framework kura.user.config=/tmp/kura/user kura.plugins=/tmp/kura/plugins kura.packages=/tmp/kura/data/packages kura.data=/tmp/kura/data kura.tmp=/tmp/kura/tmp kura.snapshots=/tmp/kura/user/snapshots kura.snapshots.count=10 kura.have.net.admin=false # os.arch= Fetch from Java # os.name= Fetch from Java # os.version= Fetch from Java os.distribution=DevOsDitribution os.distribution.version=DevOsDitributionVersion # java.version= Fetch from Java # java.vendor= Fetch from Java # java.vm.name= Fetch from Java # java.vm.version= Fetch from Java # java.home= Fetch from Java # file.separator= Fetch from Java ## ----------------------------------------------------------------------------- ## File upload settings ## ----------------------------------------------------------------------------- # default 10240 file.upload.in.memory.size.threshold=10240 # -1: unlimited (default) file.upload.size.max=-1 file.command.zip.max.size=100 file.command.zip.max.number=1024 ## ----------------------------------------------------------------------------- ## Deployment Agent settings ## ----------------------------------------------------------------------------- # see copyURLToFile() http://commons.apache.org/proper/commons-io/javadocs/api-2.4/index.html dpa.connection.timeout = 60000 dpa.read.timeout = 60000 ## ----------------------------------------------------------------------------- ## Cloud Connection Status settings ## ----------------------------------------------------------------------------- #1. Cloud Connection Status on system log #The Cloud Connection Status will be indicated in the log files, and nowere else ccs.status.notification.url=ccs:log #2. Cloud Connection Status on LED #The Cloud Connection Status will be indicated by a blinking LED connected to the system GPIOs #The URL should identify the GPIO to be used, either by name or by terminal index as defined by Kura GpioService. # Syntax for using GPIO terminal index: #ccs.status.notification.url=ccs:led:16 #ccs.status.notification.url=ccs:led:terminal:16 # Syntax for using GPIO name: #ccs.status.notification.url=ccs:led:name:LED_1 #3. Cloud Connection Status disabled #Disables the Cloud Connection Status service #ccs.status.notification.url=ccs:none ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/src/main/resources/log4j.xml ================================================ %d{ISO8601} [%t] %-5p %c{1.} - %m%n%throwable{full} ================================================ FILE: kura/emulator/org.eclipse.kura.emulator/src/main/resources/snapshot_0.xml ================================================ false org.eclipse.kura.watchdog.WatchdogService 10000 true 123 3600 java-ntp true 10000 0.pool.ntp.org org.eclipse.kura.clock.ClockService true username {{client-id-placeholder}} account-name mqtt://broker-url:1883/ false file $EDC/#account-name/#client-id/MQTT/LWT 30 org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport password 20 0 4 0 60 true 1000 10 false 60 org.eclipse.kura.data.DataService 9 900 (kura.service.pid=org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport) true Kura Emulator (kura.service.pid=org.eclipse.kura.data.DataService) data data 0 HEATER false 7 org.eclipse.kura.cloud.publisher.CloudPublisher org.eclipse.kura.cloud.CloudService heaterPublisher org.eclipse.kura.cloud.publisher.CloudPublisher-1587372517474-4 (kura.service.pid=heaterPublisher) TLSv1.2 true (kura.service.pid=SSLKeystore) org.eclipse.kura.ssl.SslManagerService 100 8080 [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="}}] [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin"},{"name":"kura.permission.kura.device"},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.packages.admin"},{"name":"kura.permission.kura.wires.admin"},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.deploy"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.security"},{"name":"kura.permission.rest.system"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] org.eclipse.kura.emulator/src/main/resources/cacerts.ks Y2hhbmdlaXQ= false org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl SSLKeystore SA 10 jdbc:h2:mem:kuradb org.eclipse.kura.core.db.H2DbService 900 org.eclipse.kura.db.H2DbService ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.clock Bundle-SymbolicName: org.eclipse.kura.emulator.clock;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.clock; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.clock;version="[1.0,1.1)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.0", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/OSGI-INF/clock.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/OSGI-INF/metatype/org.eclipse.kura.clock.ClockService.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/build.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.clock 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.clock/src/main/java/org/eclipse/kura/emulator/clock/ClockServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.clock; import java.util.Date; import java.util.Map; import org.eclipse.kura.KuraException; import org.eclipse.kura.clock.ClockService; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.EventAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ClockServiceImpl implements ConfigurableComponent, ClockService { private static final Logger logger = LoggerFactory.getLogger(ClockServiceImpl.class); @SuppressWarnings("unused") private ComponentContext ctx; @SuppressWarnings("unused") private EventAdmin eventAdmin; @SuppressWarnings("unused") private Map properties; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void unsetEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { logger.info("Activate. Current Time: {}", new Date()); // save the bundle context this.ctx = componentContext; } protected void deactivate(ComponentContext componentContext) { logger.info("Deactivate..."); } public void updated(Map properties) { logger.info("Updated..."); try { // save the properties this.properties = properties; } catch (Throwable t) { logger.error("Error updating ClockService Configuration", t); } } // ---------------------------------------------------------------- // // Master Client Management APIs // // ---------------------------------------------------------------- @Override public Date getLastSync() throws KuraException { return new Date(); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.gpio Bundle-SymbolicName: org.eclipse.kura.emulator.gpio;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.gpio; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura.gpio; version="[1.2,1.3)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/OSGI-INF/gpio.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/build.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api,\ org.eclipse.equinox.metatype src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.gpio 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/src/main/java/org/eclipse/kura/emulator/gpio/EmulatedPin.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.emulator.gpio; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.eclipse.kura.gpio.KuraClosedDeviceException; import org.eclipse.kura.gpio.KuraGPIODescription; import org.eclipse.kura.gpio.KuraGPIODeviceException; import org.eclipse.kura.gpio.KuraGPIODirection; import org.eclipse.kura.gpio.KuraGPIOMode; import org.eclipse.kura.gpio.KuraGPIOPin; import org.eclipse.kura.gpio.KuraGPIOTrigger; import org.eclipse.kura.gpio.KuraUnavailableDeviceException; import org.eclipse.kura.gpio.PinStatusListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EmulatedPin implements KuraGPIOPin { private static final Logger logger = LoggerFactory.getLogger(EmulatedPin.class); private static final String UNKNOWN = "unknown"; private boolean internalValue = false; private String pinName = null; private int pinController = -1; private int pinLine = -1; private KuraGPIODirection direction = KuraGPIODirection.OUTPUT; private KuraGPIOMode mode = KuraGPIOMode.OUTPUT_OPEN_DRAIN; private KuraGPIOTrigger trigger = KuraGPIOTrigger.NONE; public EmulatedPin(String pinName) { super(); this.pinName = pinName; this.pinController = 0; this.pinLine = 0; } public EmulatedPin(int pinIndex) { super(); this.pinName = UNKNOWN; this.pinController = pinIndex / 1000; this.pinLine = pinIndex % 1000; } public EmulatedPin(String pinName, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) { super(); this.pinName = pinName; this.pinController = 0; this.pinLine = 0; this.direction = direction; this.mode = mode; this.trigger = trigger; } public EmulatedPin(int pinIndex, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) { super(); this.pinName = UNKNOWN; this.pinController = pinIndex / 1000; this.pinLine = pinIndex % 1000; this.direction = direction; this.mode = mode; this.trigger = trigger; } @Override public void setValue(boolean active) throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException { this.internalValue = active; logger.debug("Emulated GPIO Pin {}:{}:{} changed to {}", this.pinName, this.pinController, this.pinLine, active ? "on" : "off"); } @Override public boolean getValue() throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException { return this.internalValue; } @Override public void addPinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException { // Do nothing } @Override public void removePinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException { // Do nothing } @Override public void open() throws KuraGPIODeviceException, KuraUnavailableDeviceException, IOException { logger.info("Emulated GPIO Pin {}:{}:{} open.", this.pinName, this.pinController, this.pinLine); } @Override public void close() throws IOException { logger.info("Emulated GPIO Pin {}:{}:{} closed.", this.pinName, this.pinController, this.pinLine); } @Override public String toString() { return "GPIO Pin Name " + this.pinName + " Controller #" + this.pinController + " Line #" + this.pinLine; } @Override public KuraGPIODirection getDirection() { return this.direction; } @Override public KuraGPIOMode getMode() { return this.mode; } @Override public KuraGPIOTrigger getTrigger() { return this.trigger; } @Override public String getName() { return this.pinName; } @Override public int getIndex() { return this.pinController * 1000 + this.pinLine; } @Override public boolean isOpen() { return true; } @Override public KuraGPIODescription getDescription() { Map properties = new HashMap<>(); properties.put("controller", Integer.toString(this.pinController)); properties.put("line", Integer.toString(this.pinLine)); properties.put("name", this.pinName); properties.put(KuraGPIODescription.DISPLAY_NAME_PROPERTY, this.pinName + ":" + this.pinController + ":" + this.pinLine); return new KuraGPIODescription(properties); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.gpio/src/main/java/org/eclipse/kura/emulator/gpio/GpioServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.emulator.gpio; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.kura.gpio.GPIOService; import org.eclipse.kura.gpio.KuraGPIODescription; import org.eclipse.kura.gpio.KuraGPIODirection; import org.eclipse.kura.gpio.KuraGPIOMode; import org.eclipse.kura.gpio.KuraGPIOPin; import org.eclipse.kura.gpio.KuraGPIOTrigger; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GpioServiceImpl implements GPIOService { private static final Logger logger = LoggerFactory.getLogger(GpioServiceImpl.class); private final HashMap pins = new HashMap<>(); private final List pinDescriptions = new ArrayList<>(); protected void activate(ComponentContext componentContext) { logger.debug("activating emulated GPIOService"); for (int chip = 0; chip < 2; chip++) { for (int line = 0; line < 5; line++) { String name = "GPIOchip" + chip + "line" + line; Map properties = new HashMap<>(); properties.put("controller", String.valueOf(chip)); properties.put("line", String.valueOf(line)); properties.put(KuraGPIODescription.DISPLAY_NAME_PROPERTY, name + ":" + chip + ":" + line); KuraGPIODescription desc = new KuraGPIODescription(properties); this.pinDescriptions.add(desc); this.pins.put(chip * 1000 + line, name); } } } protected void deactivate(ComponentContext componentContext) { logger.debug("deactivating emulated GPIOService"); } @Override public KuraGPIOPin getPinByName(String pinName) { if (pinName == null || pinName.isEmpty()) { throw new IllegalArgumentException("pinName cannot be null"); } return new EmulatedPin(pinName); } @Override public KuraGPIOPin getPinByName(String pinName, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) { if (pinName == null || pinName.isEmpty()) { throw new IllegalArgumentException("pinName cannot be null"); } return new EmulatedPin(pinName, direction, mode, trigger); } @Override public KuraGPIOPin getPinByTerminal(int terminal) { if (terminal < 0) { throw new IllegalArgumentException("terminal cannot be negative"); } return new EmulatedPin(terminal); } @Override public KuraGPIOPin getPinByTerminal(int terminal, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) { if (terminal < 0) { throw new IllegalArgumentException("terminal cannot be negative"); } return new EmulatedPin(terminal, direction, mode, trigger); } @Override public Map getAvailablePins() { return Collections.unmodifiableMap(this.pins); } @Override public List getPins(Map description) { if (description == null || description.isEmpty() || !description.containsKey("name")) { throw new IllegalArgumentException("description cannot be null or empty and must contain 'name' key"); } return Arrays.asList(new EmulatedPin(description.get("name"))); } @Override public List getPins(Map description, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger) { if (description == null || description.isEmpty() || !description.containsKey("name")) { throw new IllegalArgumentException("description cannot be null or empty and must contain 'name' key"); } return Arrays.asList(new EmulatedPin(description.get("name"), direction, mode, trigger)); } @Override public List getAvailablePinDescriptions() { return Collections.unmodifiableList(this.pinDescriptions); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.net Bundle-SymbolicName: org.eclipse.kura.emulator.net;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.net; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.emulator;version="[1.0,2.0)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.net.modem;version="[2.0,3.0)", org.eclipse.kura.net.wifi;version="[2.0,3.0)", org.eclipse.kura.usb;version="[1.3,2.0)", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/OSGI-INF/network.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/build.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.net 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/AbstractNetInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.net; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetConfigIP4; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetInterfaceAddressConfig; import org.eclipse.kura.net.NetInterfaceState; import org.eclipse.kura.net.NetInterfaceStatus; import org.eclipse.kura.usb.UsbDevice; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractNetInterface implements NetInterface { private static final Logger logger = LoggerFactory.getLogger(AbstractNetInterface.class); private String name; private byte[] hardwareAddress; private boolean loopback; private boolean pointToPoint; private boolean virtual; private boolean supportsMulticast; private boolean up; private int mtu; private UsbDevice usbDevice; private String driver; private String driverVersion; private String firmwareVersion; private NetInterfaceState state; private boolean autoConnect; private List interfaceAddresses; protected AbstractNetInterface(String name) { super(); this.name = name; this.interfaceAddresses = new ArrayList<>(); } protected AbstractNetInterface(NetInterface other) { super(); this.name = other.getName(); this.hardwareAddress = other.getHardwareAddress(); this.loopback = other.isLoopback(); this.pointToPoint = other.isPointToPoint(); this.virtual = other.isVirtual(); this.supportsMulticast = other.supportsMulticast(); this.up = other.isUp(); this.mtu = other.getMTU(); this.usbDevice = other.getUsbDevice(); this.driver = other.getDriver(); this.driverVersion = other.getDriverVersion(); this.firmwareVersion = other.getFirmwareVersion(); this.state = other.getState(); this.autoConnect = other.isAutoConnect(); this.interfaceAddresses = new ArrayList<>(); // note - copying of interfaceAddresses are handled in the subclasses } @Override public String getName() { return this.name; } public void setName(String name) { this.name = name; } @Override public byte[] getHardwareAddress() { return this.hardwareAddress; } @Override public boolean isLoopback() { return this.loopback; } @Override public boolean isPointToPoint() { return this.pointToPoint; } @Override public boolean isVirtual() { return this.virtual; } @Override public boolean supportsMulticast() { return this.supportsMulticast; } @Override public boolean isUp() { return this.up; } @Override public int getMTU() { return this.mtu; } public void setMTU(int mtu) { this.mtu = mtu; } @Override public String getDriver() { return this.driver; } public void setDriver(String driver) { this.driver = driver; } @Override public String getDriverVersion() { return this.driverVersion; } public void setDriverVersion(String driverVersion) { this.driverVersion = driverVersion; } @Override public String getFirmwareVersion() { return this.firmwareVersion; } public void setFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; } @Override public NetInterfaceState getState() { return this.state; } public void setState(NetInterfaceState state) { this.state = state; } @Override public UsbDevice getUsbDevice() { return this.usbDevice; } public void setHardwareAddress(byte[] hardwareAddress) { this.hardwareAddress = hardwareAddress; } public void setLoopback(boolean loopback) { this.loopback = loopback; } public void setPointToPoint(boolean pointToPoint) { this.pointToPoint = pointToPoint; } public void setVirtual(boolean virtual) { this.virtual = virtual; } public void setSupportsMulticast(boolean supportsMulticast) { this.supportsMulticast = supportsMulticast; } public void setUp(boolean up) { this.up = up; } public void setUsbDevice(UsbDevice usbDevice) { this.usbDevice = usbDevice; } @Override public boolean isAutoConnect() { return this.autoConnect; } public void setAutoConnect(boolean autoConnect) { this.autoConnect = autoConnect; } @Override public List getNetInterfaceAddresses() { if (this.interfaceAddresses != null) { return Collections.unmodifiableList(this.interfaceAddresses); } return Collections.emptyList(); } public void setNetInterfaceAddresses(List interfaceAddresses) { this.interfaceAddresses = interfaceAddresses; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("name=").append(this.name); if (this.hardwareAddress != null && this.hardwareAddress.length == 6) { sb.append(" :: hardwareAddress=").append(macToString(this.hardwareAddress)); } sb.append(" :: loopback=").append(this.loopback).append(" :: pointToPoint=").append(this.pointToPoint) .append(" :: virtual=").append(this.virtual).append(" :: supportsMulticast=") .append(this.supportsMulticast).append(" :: up=").append(this.up).append(" :: mtu=").append(this.mtu); if (this.usbDevice != null) { sb.append(" :: usbDevice=").append(this.usbDevice); } sb.append(" :: driver=").append(this.driver).append(" :: driverVersion=").append(this.driverVersion) .append(" :: firmwareVersion=").append(this.firmwareVersion).append(" :: state=").append(this.state) .append(" :: autoConnect=").append(this.autoConnect); if (this.interfaceAddresses != null && !this.interfaceAddresses.isEmpty()) { sb.append(" :: InterfaceAddress="); for (T interfaceAddress : this.interfaceAddresses) { sb.append(interfaceAddress).append(" "); } } return sb.toString(); } private static String macToString(byte[] mac) { if (mac == null || mac.length != 6) { throw new IllegalArgumentException("mac is null or invalid"); } String[] items = new String[6]; for (int i = 0; i < 6; i++) { String octet = Integer.toHexString(mac[i] & 0xFF).toUpperCase(); if (octet.length() == 1) { octet = "0" + octet; } items[i] = octet; } return String.join(":", items); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.autoConnect ? 1231 : 1237); result = prime * result + (this.driver == null ? 0 : this.driver.hashCode()); result = prime * result + (this.driverVersion == null ? 0 : this.driverVersion.hashCode()); result = prime * result + (this.firmwareVersion == null ? 0 : this.firmwareVersion.hashCode()); result = prime * result + Arrays.hashCode(this.hardwareAddress); result = prime * result + (this.interfaceAddresses == null ? 0 : this.interfaceAddresses.hashCode()); result = prime * result + (this.loopback ? 1231 : 1237); result = prime * result + this.mtu; result = prime * result + (this.name == null ? 0 : this.name.hashCode()); result = prime * result + (this.pointToPoint ? 1231 : 1237); result = prime * result + (this.state == null ? 0 : this.state.hashCode()); result = prime * result + (this.supportsMulticast ? 1231 : 1237); result = prime * result + (this.up ? 1231 : 1237); result = prime * result + (this.usbDevice == null ? 0 : this.usbDevice.hashCode()); result = prime * result + (this.virtual ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof AbstractNetInterface)) { return false; } AbstractNetInterface other = (AbstractNetInterface) obj; if (this.autoConnect != other.autoConnect) { return false; } if (this.driver == null) { if (other.driver != null) { return false; } } else if (!this.driver.equals(other.driver)) { return false; } if (this.driverVersion == null) { if (other.driverVersion != null) { return false; } } else if (!this.driverVersion.equals(other.driverVersion)) { return false; } if (this.firmwareVersion == null) { if (other.firmwareVersion != null) { return false; } } else if (!this.firmwareVersion.equals(other.firmwareVersion)) { return false; } if (!Arrays.equals(this.hardwareAddress, other.hardwareAddress)) { return false; } if (this.interfaceAddresses == null) { if (other.interfaceAddresses != null) { return false; } } else if (!this.interfaceAddresses.equals(other.interfaceAddresses)) { return false; } if (this.loopback != other.loopback) { return false; } if (this.mtu != other.mtu) { return false; } if (this.name == null) { if (other.name != null) { return false; } } else if (!this.name.equals(other.name)) { return false; } if (this.pointToPoint != other.pointToPoint) { return false; } if (this.state != other.state) { return false; } if (this.supportsMulticast != other.supportsMulticast) { return false; } if (this.up != other.up) { return false; } if (this.usbDevice == null) { if (other.usbDevice != null) { return false; } } else if (!this.usbDevice.equals(other.usbDevice)) { return false; } if (this.virtual != other.virtual) { return false; } return true; } public NetInterfaceAddressConfig getNetInterfaceAddressConfig() throws KuraException { if (this.getNetInterfaceAddresses() == null || this.getNetInterfaceAddresses().isEmpty()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, "Empty NetInterfaceAddressConfig list"); } return (NetInterfaceAddressConfig) this.getNetInterfaceAddresses().get(0); } /** * Returns a list of network configurations * * @return list of network configurations as {@link List} */ public List getNetConfigs() { List ret = new ArrayList<>(); try { List netConfigs = getNetInterfaceAddressConfig().getConfigs(); if (netConfigs != null) { ret = netConfigs; } } catch (KuraException e) { logger.error("Failed to obtain NetConfigs", e); } return ret; } /** * Reports interface status * * @return interface status as {@link NetInterfaceStatus} */ public NetInterfaceStatus getInterfaceStatus() { List netConfigs = getNetConfigs(); if (netConfigs == null) { return NetInterfaceStatus.netIPv4StatusUnknown; } NetInterfaceStatus status = NetInterfaceStatus.netIPv4StatusUnknown; for (NetConfig netConfig : netConfigs) { if (netConfig instanceof NetConfigIP4) { status = ((NetConfigIP4) netConfig).getStatus(); break; } } return status; } /** * Reports IPv4 configuration * * @return IPv4 configuration as {@link NetConfigIP4} */ public NetConfigIP4 getIP4config() { NetConfigIP4 netConfigIP4 = null; List netConfigs = getNetConfigs(); for (NetConfig netConfig : netConfigs) { if (netConfig instanceof NetConfigIP4) { netConfigIP4 = (NetConfigIP4) netConfig; break; } } return netConfigIP4; } /** * Reports if interface is managed by the NetAdmin * * @return boolean */ public boolean isInterfaceManaged() { NetInterfaceStatus status = getInterfaceStatus(); return status != NetInterfaceStatus.netIPv4StatusUnmanaged && status != NetInterfaceStatus.netIPv4StatusUnknown; } /** * Reports if interface is enabled in configuration * * @return boolean */ public boolean isInterfaceEnabled() { NetInterfaceStatus status = getInterfaceStatus(); return status == NetInterfaceStatus.netIPv4StatusL2Only || status == NetInterfaceStatus.netIPv4StatusEnabledLAN || status == NetInterfaceStatus.netIPv4StatusEnabledWAN; } /** * Reports if interface status is unknown * * @return boolean */ public boolean isInterfaceUnknown() { return getInterfaceStatus() == NetInterfaceStatus.netIPv4StatusUnknown; } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/EmulatedNetworkServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.net; import java.net.SocketException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.emulator.Emulator; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetInterfaceState; import org.eclipse.kura.net.NetworkService; import org.eclipse.kura.net.NetworkState; import org.eclipse.kura.net.modem.ModemDevice; import org.eclipse.kura.net.wifi.WifiAccessPoint; import org.eclipse.kura.usb.UsbNetDevice; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EmulatedNetworkServiceImpl implements NetworkService { private static final Logger logger = LoggerFactory.getLogger(EmulatedNetworkServiceImpl.class); @SuppressWarnings("unused") private Emulator emulator; @SuppressWarnings("unused") private ComponentContext ctx; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setEmulator(Emulator emulator) { this.emulator = emulator; } public void unsetEmulator(Emulator emulator) { this.emulator = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { // // save the bundle context this.ctx = componentContext; } protected void deactivate(ComponentContext componentContext) { this.ctx = null; } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public NetworkState getState() { java.net.InetAddress jnAddress = getFirstActiveInetAddress(); if (jnAddress == null) { return NetworkState.DISCONNECTED; } else if (jnAddress.isLoopbackAddress() || jnAddress.isLinkLocalAddress()) { return NetworkState.CONNECTED_LOCAL; } else if (jnAddress.isSiteLocalAddress()) { return NetworkState.CONNECTED_SITE; } else { return NetworkState.CONNECTED_GLOBAL; } } @Override public NetInterfaceState getState(String interfaceName) { // Returned unknown state for the emulated network service. return NetInterfaceState.UNKNOWN; } @Override public List getAllNetworkInterfaceNames() throws KuraException { List interfaceNames = new ArrayList<>(); java.net.NetworkInterface jnInterface = null; Enumeration interfaces = null; try { interfaces = java.net.NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { jnInterface = interfaces.nextElement(); interfaceNames.add(jnInterface.getName()); } } catch (SocketException e) { throw new KuraException(KuraErrorCode.IO_ERROR, e); } return interfaceNames; } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public List> getNetworkInterfaces() throws KuraException { IPAddress netAddress = null; NetInterfaceAddressImpl addressImpl = null; List addresses = null; List> interfaces = new ArrayList<>(); EthernetInterfaceImpl ethInterface = null; java.net.NetworkInterface jnInterface = null; List jnInterfaceAddresses = null; Enumeration jnInterfaces = null; try { jnInterfaces = java.net.NetworkInterface.getNetworkInterfaces(); while (jnInterfaces.hasMoreElements()) { jnInterface = jnInterfaces.nextElement(); ethInterface = new EthernetInterfaceImpl(jnInterface.getName()); ethInterface.setVirtual(jnInterface.isVirtual()); ethInterface.setState(NetInterfaceState.ACTIVATED); ethInterface.setAutoConnect(true); byte[] hwAddr = null; boolean isUp = false; boolean isLoop = false; int mtu = 0; boolean isP2p = false; boolean multi = false; try { hwAddr = jnInterface.getHardwareAddress(); isUp = jnInterface.isUp(); isLoop = jnInterface.isLoopback(); mtu = jnInterface.getMTU(); isP2p = jnInterface.isPointToPoint(); multi = jnInterface.supportsMulticast(); } catch (Exception e) { logger.warn("Exception while getting information for interface {}:{}", jnInterface.getName(), e.getMessage()); } ethInterface.setHardwareAddress(hwAddr); ethInterface.setLinkUp(isUp); ethInterface.setLoopback(isLoop); ethInterface.setMTU(mtu); ethInterface.setPointToPoint(isP2p); ethInterface.setSupportsMulticast(multi); ethInterface.setUp(isUp); addresses = new ArrayList<>(); jnInterfaceAddresses = jnInterface.getInterfaceAddresses(); for (java.net.InterfaceAddress jnInterfaceAddress : jnInterfaceAddresses) { netAddress = IPAddress.getByAddress(jnInterfaceAddress.getAddress().getAddress()); addressImpl = new NetInterfaceAddressImpl(); addressImpl.setAddress(netAddress); if (jnInterfaceAddress.getBroadcast() != null) { addressImpl .setBroadcast(IPAddress.getByAddress(jnInterfaceAddress.getBroadcast().getAddress())); } addressImpl.setNetworkPrefixLength(jnInterfaceAddress.getNetworkPrefixLength()); addresses.add(addressImpl); } ethInterface.setNetInterfaceAddresses(addresses); interfaces.add(ethInterface); } } catch (Exception e) { throw new KuraException(KuraErrorCode.IO_ERROR, e); } return interfaces; } @Override public List getAllWifiAccessPoints() { return Collections.emptyList(); } @Override public List getWifiAccessPoints(String wifiInterfaceName) { return Collections.emptyList(); } @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public List> getActiveNetworkInterfaces() throws KuraException { IPAddress netAddress = null; NetInterfaceAddressImpl addressImpl = null; List addresses = null; List> interfaces = new ArrayList<>(); EthernetInterfaceImpl ethInterface = null; java.net.NetworkInterface jnInterface = null; List jnInterfaceAddresses = null; Enumeration jnInterfaces = null; try { jnInterfaces = java.net.NetworkInterface.getNetworkInterfaces(); while (jnInterfaces.hasMoreElements()) { try { jnInterface = jnInterfaces.nextElement(); if (jnInterface.isUp() && !jnInterface.isVirtual() && !jnInterface.isLoopback() && !jnInterface.isPointToPoint() && jnInterface.getHardwareAddress() != null && !jnInterface.getInterfaceAddresses().isEmpty()) { ethInterface = new EthernetInterfaceImpl(jnInterface.getName()); ethInterface.setVirtual(jnInterface.isVirtual()); ethInterface.setState(NetInterfaceState.ACTIVATED); ethInterface.setAutoConnect(true); byte[] hwAddr = null; boolean isUp = false; boolean isLoop = false; int mtu = 0; boolean isP2p = false; boolean multi = false; try { hwAddr = jnInterface.getHardwareAddress(); isUp = jnInterface.isUp(); isLoop = jnInterface.isLoopback(); mtu = jnInterface.getMTU(); isP2p = jnInterface.isPointToPoint(); multi = jnInterface.supportsMulticast(); } catch (Exception e) { logger.warn("Exception while getting information for interface " + jnInterface.getName(), e); } ethInterface.setHardwareAddress(hwAddr); ethInterface.setLinkUp(isUp); ethInterface.setLoopback(isLoop); ethInterface.setMTU(mtu); ethInterface.setPointToPoint(isP2p); ethInterface.setSupportsMulticast(multi); ethInterface.setUp(isUp); addresses = new ArrayList<>(); jnInterfaceAddresses = jnInterface.getInterfaceAddresses(); for (java.net.InterfaceAddress jnInterfaceAddress : jnInterfaceAddresses) { netAddress = IPAddress.getByAddress(jnInterfaceAddress.getAddress().getAddress()); addressImpl = new NetInterfaceAddressImpl(); addressImpl.setAddress(netAddress); if (jnInterfaceAddress.getBroadcast() != null) { addressImpl.setBroadcast( IPAddress.getByAddress(jnInterfaceAddress.getBroadcast().getAddress())); } addressImpl.setNetworkPrefixLength(jnInterfaceAddress.getNetworkPrefixLength()); addresses.add(addressImpl); } ethInterface.setNetInterfaceAddresses(addresses); interfaces.add(ethInterface); } } catch (SocketException se) { logger.warn("Exception while getting information for interface " + jnInterface.getName(), se); } } } catch (Exception e) { throw new KuraException(KuraErrorCode.IO_ERROR, e); } return interfaces; } // --------------------------------------------------------- // // Private methods // // --------------------------------------------------------- private java.net.InetAddress getFirstActiveInetAddress() { java.net.InetAddress jnAddress = null; java.net.NetworkInterface jnInterface = null; try { Enumeration interfaces = null; // search for a non loopback interface interfaces = java.net.NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { jnInterface = interfaces.nextElement(); if (jnInterface.isUp() && !jnInterface.isLoopback() && !jnInterface.isVirtual()) { Enumeration addresses = null; addresses = jnInterface.getInetAddresses(); while (addresses.hasMoreElements()) { java.net.InetAddress address = addresses.nextElement(); if (address instanceof java.net.Inet4Address && !address.isLoopbackAddress()) { jnAddress = address; break; } } } if (jnAddress != null) { break; } // get a loopback interface interfaces = java.net.NetworkInterface.getNetworkInterfaces(); while (interfaces.hasMoreElements()) { jnInterface = interfaces.nextElement(); if (jnInterface.isUp() && !jnInterface.isVirtual()) { Enumeration addresses = null; addresses = jnInterface.getInetAddresses(); while (addresses.hasMoreElements()) { java.net.InetAddress address = addresses.nextElement(); if (address instanceof java.net.Inet4Address) { jnAddress = address; break; } } } } } } catch (SocketException e) { logger.error("Error getting IP address", e); } return jnAddress; } @Override public String getModemUsbPort(String interfaceName) { return null; } @Override public String getModemPppPort(ModemDevice modemDevice) throws KuraException { return null; } @Override public String getModemPppInterfaceName(String usbPath) { return null; } @Override public Optional getModemDevice(String usbPath) { return Optional.empty(); } @Override public Optional getUsbNetDevice(String interfaceName) { return Optional.empty(); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/EthernetInterfaceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.net; import java.util.ArrayList; import java.util.List; import org.eclipse.kura.net.EthernetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetInterfaceType; public class EthernetInterfaceImpl extends AbstractNetInterface implements EthernetInterface { private boolean linkUp; public EthernetInterfaceImpl(String name) { super(name); } @SuppressWarnings("unchecked") public EthernetInterfaceImpl(EthernetInterface other) { super(other); this.linkUp = other.isLinkUp(); // Copy the NetInterfaceAddresses List otherNetInterfaceAddresses = other.getNetInterfaceAddresses(); ArrayList interfaceAddresses = new ArrayList<>(); if (otherNetInterfaceAddresses != null) { for (NetInterfaceAddress netInterfaceAddress : otherNetInterfaceAddresses) { NetInterfaceAddressImpl copiedInterfaceAddressImpl = new NetInterfaceAddressImpl(netInterfaceAddress); interfaceAddresses.add((T) copiedInterfaceAddressImpl); } } setNetInterfaceAddresses(interfaceAddresses); } @Override public NetInterfaceType getType() { return NetInterfaceType.ETHERNET; } @Override public boolean isLinkUp() { return this.linkUp; } public void setLinkUp(boolean linkUp) { this.linkUp = linkUp; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()).append(" :: linkUp=").append(this.linkUp); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (this.linkUp ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof EthernetInterfaceImpl)) { return false; } EthernetInterfaceImpl other = (EthernetInterfaceImpl) obj; if (this.linkUp != other.linkUp) { return false; } return true; } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.net/src/main/java/org/eclipse/kura/emulator/net/NetInterfaceAddressImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.net; import java.util.List; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetInterfaceAddress; public class NetInterfaceAddressImpl implements NetInterfaceAddress { private IPAddress address; private short networkPrefixLength; private IPAddress netmask; private IPAddress gateway; private IPAddress broadcast; private List dnsAddresses; public NetInterfaceAddressImpl() { } public NetInterfaceAddressImpl(NetInterfaceAddress other) { super(); this.address = other.getAddress(); this.networkPrefixLength = other.getNetworkPrefixLength(); this.netmask = other.getNetmask(); this.gateway = other.getGateway(); this.broadcast = other.getBroadcast(); this.dnsAddresses = other.getDnsServers(); } @Override public IPAddress getAddress() { return this.address; } public void setAddress(IPAddress address) { this.address = address; } @Override public short getNetworkPrefixLength() { return this.networkPrefixLength; } public void setNetworkPrefixLength(short networkPrefixLength) { this.networkPrefixLength = networkPrefixLength; } @Override public IPAddress getNetmask() { return this.netmask; } public void setNetmask(IPAddress netmask) { this.netmask = netmask; } @Override public IPAddress getGateway() { return this.gateway; } public void setGateway(IPAddress gateway) { this.gateway = gateway; } @Override public IPAddress getBroadcast() { return this.broadcast; } public void setBroadcast(IPAddress broadcast) { this.broadcast = broadcast; } @Override public List getDnsServers() { return this.dnsAddresses; } public void setDnsServers(List dnsAddresses) { this.dnsAddresses = dnsAddresses; } @Override public boolean equals(Object obj) { if (!(obj instanceof NetInterfaceAddress)) { return false; } NetInterfaceAddress other = (NetInterfaceAddress) obj; return this.networkPrefixLength == other.getNetworkPrefixLength() && compare(this.address, other.getAddress()) && compare(this.netmask, other.getNetmask()) && compare(this.gateway, other.getGateway()) && compare(this.broadcast, other.getBroadcast()) && compare(this.dnsAddresses, other.getDnsServers()); } protected boolean compare(Object obj1, Object obj2) { return obj1 == null ? obj2 == null : obj1.equals(obj2); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.address == null ? 0 : this.address.hashCode()); result = prime * result + (this.broadcast == null ? 0 : this.broadcast.hashCode()); result = prime * result + (this.dnsAddresses == null ? 0 : this.dnsAddresses.hashCode()); result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode()); result = prime * result + (this.netmask == null ? 0 : this.netmask.hashCode()); result = prime * result + this.networkPrefixLength; return result; } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.position Bundle-SymbolicName: org.eclipse.kura.emulator.position;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.position; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: javax.xml.parsers, javax.xml.stream, org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.position;version="[1.4,1.5)", org.osgi.framework;version="1.7.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.0", org.osgi.util.measurement;version="1.0.1", org.osgi.util.position;version="1.0.1", org.slf4j;version="1.6.4", org.xml.sax, org.xml.sax.helpers Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/OSGI-INF/metatype/org.eclipse.kura.position.PositionService.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/OSGI-INF/position.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.position 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ${project.basedir}/../../test/org.eclipse.kura.emulator.position.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/GpsPoint.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.position; public class GpsPoint { private final double latitude; private final double longitude; private final double altitude; private final String time; public GpsPoint(double latitude, double longitude, double altitude, String time) { this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; this.time = time; } public double getLatitude() { return this.latitude; } public double getLongitude() { return this.longitude; } public double getAltitude() { return this.altitude; } public String getTime() { return this.time; } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/GpsXmlHandler.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.emulator.position; import java.util.ArrayList; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; public class GpsXmlHandler extends DefaultHandler { private static final String LABEL = "org.eclipse.kura.app.demo.kura.training.console.GpsXmlHandler: "; // Valid Elements in the xml file private static final String TAG_TRACK_POINT = "trkpt"; private static final String TAG_ELEVATION = "ele"; private static final String TAG_TIME = "time"; private final ArrayList gpsPoints; private String latitude; private String longitude; private String elevation; private String time; private boolean foundTrackPoint = false; private boolean foundElevation = false; private boolean foundTime = false; public GpsXmlHandler() { this.gpsPoints = new ArrayList(); this.latitude = null; this.longitude = null; this.elevation = null; this.time = null; } @Override public void startElement(String uri, String localName, String elementName, Attributes attributes) { if (TAG_TRACK_POINT.equals(elementName)) { this.foundTrackPoint = true; if (attributes.getLength() == 2) { for (int i = 0; i < attributes.getLength(); i++) { if (attributes.getQName(i).compareTo("lat") == 0) { this.latitude = attributes.getValue(i); } else if (attributes.getQName(i).compareTo("lon") == 0) { this.longitude = attributes.getValue(i); } else { System.out.println(LABEL + "invalid attribute in trkpt element: " + attributes.getQName(i)); } } } else { System.out.println(LABEL + "there must be two attributes (lat and lon) in the trkpt element"); } this.elevation = null; this.time = null; } else if (TAG_ELEVATION.equals(elementName)) { this.foundElevation = true; } else if (TAG_TIME.equals(elementName)) { this.foundTime = true; } } @Override public void endElement(String uri, String localName, String elementName) { if (TAG_TRACK_POINT.equals(elementName)) { this.foundTrackPoint = false; if (this.latitude != null && this.longitude != null && this.elevation != null && this.time != null) { this.gpsPoints.add(new GpsPoint(Double.parseDouble(this.latitude), Double.parseDouble(this.longitude), Double.parseDouble(this.elevation), this.time)); } else { System.out.println(LABEL + "the XML file is malformed"); } } else if (TAG_ELEVATION.equals(elementName)) { this.foundElevation = false; } else if (TAG_TIME.equals(elementName)) { this.foundTime = false; } } @Override public void characters(char[] buf, int offset, int length) { String tag = new String(buf).substring(offset, offset + length).trim(); if (!this.foundTrackPoint && !this.foundElevation && !this.foundTime) { return; } if (this.foundElevation) { if (this.elevation == null) { this.elevation = new String(buf, offset, length); return; } else { this.elevation = this.elevation + new String(buf, offset, length); return; } } if (this.foundTime) { if (this.time == null) { this.time = new String(buf, offset, length); return; } else { this.time = this.time + new String(buf, offset, length); return; } } System.out.println(LABEL + "found some odd data in services.xml"); logDump(tag.getBytes()); } public GpsPoint[] getGpsPoints() { GpsPoint[] data = new GpsPoint[this.gpsPoints.size()]; for (int i = 0; i < this.gpsPoints.size(); i++) { data[i] = this.gpsPoints.get(i); } return data; } private void logDump(byte[] message) { for (int i = 0; i < message.length; i++) { if (i % 16 == 0) { if (i > 0) { System.out.println(); } System.out.print('\t'); } if (message[i] < 0x10) { System.out.print("0x0" + Integer.toHexString(message[i] & 0x0ff) + " "); } else { System.out.print("0x" + Integer.toHexString(message[i] & 0x0ff) + " "); } } } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/java/org/eclipse/kura/emulator/position/PositionServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.emulator.position; import java.io.InputStream; import java.net.URL; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.position.GNSSType; import org.eclipse.kura.position.NmeaPosition; import org.eclipse.kura.position.PositionListener; import org.eclipse.kura.position.PositionLockedEvent; import org.eclipse.kura.position.PositionService; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.EventAdmin; import org.osgi.util.measurement.Measurement; import org.osgi.util.measurement.Unit; import org.osgi.util.position.Position; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PositionServiceImpl implements PositionService, ConfigurableComponent { private static final String USE_GPSD_PROPERTY_NAME = "useGpsd"; private static final Logger logger = LoggerFactory.getLogger(PositionServiceImpl.class); private static final String SOURCE_KEY = "source"; private static final String BOSTON = "boston"; private ComponentContext ctx; private EventAdmin eventAdmin; private ScheduledExecutorService worker; private ScheduledFuture handle; private GpsPoint[] gpsPoints; private Position currentPosition; private NmeaPosition currentNmeaPosition; private Date currentTime; private int index = 0; private boolean useGpsd; private String source; public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void unsetEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map properties) { // // save the bundle context this.ctx = componentContext; this.useGpsd = false; doUpdate(properties); start(); } public void updated(Map properties) { logger.info("Updating position service"); stop(); doUpdate(properties); start(); logger.info("Updating position service. Done."); } protected void deactivate(ComponentContext componentContext) { logger.info("Stopping position service"); stop(); } private void doUpdate(Map properties) { if (properties == null) { return; } if (properties.get(USE_GPSD_PROPERTY_NAME) != null) { this.useGpsd = (Boolean) properties.get(USE_GPSD_PROPERTY_NAME); } if (this.useGpsd) { logger.info("USE GPSD"); } this.source = (String) properties.getOrDefault(SOURCE_KEY, BOSTON); } @Override public Position getPosition() { return this.currentPosition; } @Override public NmeaPosition getNmeaPosition() { return this.currentNmeaPosition; } @Override public String getNmeaTime() { return this.currentTime.toString(); } @Override public String getNmeaDate() { return this.currentTime.toString(); } @Override public boolean isLocked() { // Always return true return true; } @Override public String getLastSentence() { // Not supported in emulator mode since this is not NMEA return null; } public void start() { this.index = 0; String fileName = null; if (BOSTON.equals(this.source)) { fileName = "boston.gpx"; } else if ("denver".equals(this.source)) { fileName = "denver.gpx"; } else if ("paris".equals(this.source)) { fileName = "paris.gpx"; } else if ("test".equals(this.source)) { fileName = "test.gpx"; } GpsXmlHandler handler = new GpsXmlHandler(); SAXParserFactory factory = SAXParserFactory.newInstance(); try { factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setValidating(false); // Create the builder and parse the file SAXParser parser = factory.newSAXParser(); logger.debug("Parsing: {}", fileName); BundleContext bundleContext = this.ctx.getBundleContext(); URL url = bundleContext.getBundle().getResource(fileName); InputStream is = url.openStream(); parser.parse(is, handler); this.gpsPoints = handler.getGpsPoints(); } catch (Exception e) { logger.warn("Exception while parsing the position file", e); } // schedule a new worker based on the properties of the service this.worker = Executors.newSingleThreadScheduledExecutor(); this.handle = this.worker.scheduleAtFixedRate(this::updateGps, 0, 5, TimeUnit.SECONDS); logger.debug("posting event"); this.eventAdmin.postEvent(new PositionLockedEvent(new HashMap())); } public void stop() { if (this.handle != null) { this.handle.cancel(true); this.handle = null; } this.worker = null; } private void updateGps() { logger.debug("GPS Emulator index: {}", this.index); if (this.index + 1 == this.gpsPoints.length) { logger.debug("GPS Emulator - wrapping index"); this.index = 0; } Measurement latitude = new Measurement(java.lang.Math.toRadians(this.gpsPoints[this.index].getLatitude()), Unit.rad); Measurement longitude = new Measurement(java.lang.Math.toRadians(this.gpsPoints[this.index].getLongitude()), Unit.rad); Measurement altitude = new Measurement(this.gpsPoints[this.index].getAltitude(), Unit.m); logger.debug("Updating latitude: {}", latitude); logger.debug("Updating longitude: {}", longitude); logger.debug("Updating altitude: {}", altitude); // Measurement lat, Measurement lon, Measurement alt, Measurement speed, Measurement track this.currentTime = new Date(); this.currentPosition = new Position(latitude, longitude, altitude, null, null); this.currentNmeaPosition = new NmeaPosition(this.gpsPoints[this.index].getLatitude(), this.gpsPoints[this.index].getLongitude(), this.gpsPoints[this.index].getAltitude(), 0, 0); this.index++; } @Override public void registerListener(String listenerId, PositionListener positionListener) { // Not supported } @Override public void unregisterListener(String listenerId) { // Not supported } @Override public LocalDateTime getDateTime() { return LocalDateTime.ofInstant(this.currentTime.toInstant(), ZoneId.systemDefault()); } @Override public Set getGnssTypes() { return new HashSet<>(Arrays.asList(GNSSType.GPS)); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/boston.gpx ================================================ 1149.6149.1148.7146.7143.9141.5139134.7130.9131.4126.1123.7120.3119.8118.4114.5111.2110.7108.3107.3107.8108.3110.2114.1116.5116116116.9116.5118.4117.4116.9115.5114.1111.2109.7107.8105.4108.3104.9105.9104.9103.5105.4104.4102103103104104.4107.8107.8107.3104.9103100.6103102100.6100.198.799.299.6105.4103101.699.699.298.798.796.397.295.3100.1101.6101.6102104103.5102100.197.289.188.186.283.381.480.980.480.981.884.384.782.879.476.67776.173.770.870.368.967.966.567.968.967.46665.563.161.762.662.161.261.762.163.163.161.261.761.760.758.858.859.360.763.663.163.162.663.164.163.663.663.662.164.56668.469.872.773.274.673.272.775.173.273.774.674.274.671.872.268.466.966.966.566.567.465.566.567.964.163.663.663.663.163.66562.663.66666.566.566666665.564.562.663.163.16665.564.163.163.663.663.162.661.763.162.161.259.359.759.357.856.956.458.358.857.857.859.357.357.857.358.358.858.858.357.357.356.957.357.357.355.954.953.55353.55354.554.554.954.954.55453.55252545354.955.454.554.55353.553.55453.5535253.554.954.955.953.555.958.357.857.358.860.759.360.757.856.456.456.955.454.95453.55354.955.955.955.955.956.957.856.454.954.55455.956.956.956.956.954.958.35454.552.552.551.652.551.65252.55353.553.55351.150.650.649.649.651.150.650.65253525251.652.556.963.163.661.26565.566.564.564.164.164.163.663.664.561.762.160.761.262.663.163.159.760.261.261.261.76564.564.564.565.56566.566.566.96667.966.966.566.966.568.968.468.967.969.477.577.576.172.772.273.274.670.86668.964.561.258.358.854.95249.649.248.750.651.1525354.956.455.956.957.858.356.956.957.357.358.358.358.358.358.354.951.153.5545454545250.650.651.651.15250.649.648.246.346.347.249.249.649.649.649.649.649.649.649.649.650.649.248.750.151.153.55454.954.954.954.955.455.956.455.456.957.855.956.958.357.857.357.355.455.455.455.452.546.84235.729.925.125.125.123.223.223.223.725.1282828.528.5292830.431.932.834.336.239.641.543.942.443.443.443.944.844.846.346.845.343.442.94241.542424242.441.541.540.538.636.735.234.731.435.237.136.738.639.142.945.347.249.651.651.151.651.649.646.344.847.748.747.748.248.243.444.844.445.345.345.344.843.943.944.848.247.746.844.442.941414139.14241.54140.539.137.134.733.334.331.930.931.430.429.531.433.833.834.334.335.240.542.944.846.344.845.346.349.652.5535252.550.650.651.1525251.150.651.650.650.651.65250.15248.248.248.750.151.651.151.6535455.459.763.664.56669.470.872.273.773.275.1777878.5787877.577.57877.576.675.175.175.175.175.676.675.671.866.964.160.258.356.45453.55454.954.5545451.651.651.151.151.152.5535351.652.551.65250.648.749.248.747.245.343.442.940.539.638.638.139.64036.737.136.735.235.735.733.835.736.734.334.336.736.737.639.64038.638.64041.54037.635.736.233.332.331.934.336.735.232.828.52928.529.929.531.931.429.525.123.722.222.721.819.819.419.418.416.513.114.112.611.28.38.86.48.844.55.98.36.45.95.48.810.77.86.48.36.45.43.5330.61.61.1-0.36.410.212.614.113.614.612.612.212.211.212.213.613.615.510.710.210.710.29.811.711.710.210.29.88.38.38.88.34.58.39.810.27.86.96.96.96.46.96.96.96.97.37.35.45.45.46.9 ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/denver.gpx ================================================ Track 002 Mar 25, 2010 10:19 am 1602.000000 1605.000000 1606.000000 1608.000000 1608.000000 1607.000000 1607.000000 1607.000000 1608.000000 1609.000000 1610.000000 1610.000000 1610.000000 1609.000000 1609.000000 1609.000000 1610.000000 1611.000000 1611.000000 1611.000000 1612.000000 1613.000000 1614.000000 1614.000000 1614.000000 1613.000000 1613.000000 1612.000000 1613.000000 1614.000000 1615.000000 1615.000000 1615.000000 1614.000000 1613.000000 1611.000000 1611.000000 1611.000000 1611.000000 1611.000000 1611.000000 1611.000000 1612.000000 1612.000000 1612.000000 1613.000000 1613.000000 1612.000000 1612.000000 1612.000000 1613.000000 1613.000000 1613.000000 1613.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1615.000000 1615.000000 1615.000000 1616.000000 1616.000000 1615.000000 1616.000000 1616.000000 1617.000000 1617.000000 1617.000000 1618.000000 1618.000000 1619.000000 1619.000000 1620.000000 1620.000000 1620.000000 1621.000000 1621.000000 1621.000000 1621.000000 1621.000000 1621.000000 1621.000000 1621.000000 1622.000000 1621.000000 1621.000000 1621.000000 1622.000000 1622.000000 1622.000000 1622.000000 1622.000000 1622.000000 1623.000000 1623.000000 1623.000000 1623.000000 1624.000000 1624.000000 1624.000000 1625.000000 1627.000000 1627.000000 1628.000000 1628.000000 1628.000000 1629.000000 1629.000000 1629.000000 1628.000000 1628.000000 1628.000000 1628.000000 1628.000000 1628.000000 1628.000000 1629.000000 1630.000000 1629.000000 1629.000000 1629.000000 1628.000000 1628.000000 1627.000000 1627.000000 1627.000000 1626.000000 1626.000000 1626.000000 1626.000000 1626.000000 1622.000000 1622.000000 1622.000000 1623.000000 1623.000000 1623.000000 1623.000000 1624.000000 1624.000000 1624.000000 1624.000000 1624.000000 1625.000000 1624.000000 1624.000000 1623.000000 1623.000000 1622.000000 1621.000000 1619.000000 1618.000000 1618.000000 1617.000000 1616.000000 1615.000000 1615.000000 1615.000000 1613.000000 1613.000000 1613.000000 1613.000000 1614.000000 1614.000000 1615.000000 1615.000000 1616.000000 1616.000000 1617.000000 1617.000000 1616.000000 1616.000000 1619.000000 1619.000000 1619.000000 1619.000000 1618.000000 1618.000000 1618.000000 1618.000000 1617.000000 1617.000000 1617.000000 1619.000000 1619.000000 1619.000000 1618.000000 1618.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1618.000000 1618.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1616.000000 1616.000000 1615.000000 1615.000000 1615.000000 1616.000000 1616.000000 1616.000000 1617.000000 1618.000000 1619.000000 1619.000000 1619.000000 1619.000000 1618.000000 1618.000000 1618.000000 1619.000000 1618.000000 1618.000000 1617.000000 1616.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1617.000000 1616.000000 1615.000000 1614.000000 1614.000000 1613.000000 1611.000000 1610.000000 1610.000000 1611.000000 1611.000000 1611.000000 1611.000000 1610.000000 1610.000000 1609.000000 1611.000000 1611.000000 1612.000000 1612.000000 1613.000000 1613.000000 1613.000000 1613.000000 1614.000000 1614.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1615.000000 1614.000000 1615.000000 1615.000000 1613.000000 1612.000000 1612.000000 1612.000000 1613.000000 1611.000000 1611.000000 1612.000000 1612.000000 1611.000000 1611.000000 1610.000000 1610.000000 1610.000000 1610.000000 1611.000000 1611.000000 1612.000000 1612.000000 1613.000000 1613.000000 1613.000000 1613.000000 1614.000000 1614.000000 1614.000000 1614.000000 1613.000000 1613.000000 1613.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1615.000000 1616.000000 1615.000000 1615.000000 1615.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1614.000000 1615.000000 1614.000000 1613.000000 1613.000000 1612.000000 1612.000000 ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/paris.gpx ================================================ 162.077661.796461.892961.983761.525161.165360.332458.859758.612757.399856.686755.739855.024254.871754.800554.786654.585254.788955.197455.68556.306756.295556.262556.236155.883855.117454.168152.916751.923451.516951.087450.441249.749249.730649.75350.036850.51650.349450.043649.75649.217247.897746.583145.057644.21343.636543.349343.181943.069543.010543.096743.048942.907742.881742.864642.830742.513742.407342.275642.531642.512242.543442.543742.528442.44642.252642.208242.093542.722442.870642.879542.79642.544942.218241.103239.941338.944937.821236.601535.777835.316934.62434.25334.135133.841833.73234.026234.945235.822736.479337.147137.292937.280437.123836.625136.284536.110636.016136.130936.446236.641236.898237.283737.955838.653139.294740.162341.013841.500340.384638.974937.490336.408636.233236.427736.507236.311936.101835.773535.454235.277335.109234.824934.156233.153832.978832.401632.069132.159232.451232.54332.731732.826532.921433.023433.08132.93632.940433.025833.591634.435535.16236.050936.787736.975837.137836.633836.168935.772935.383935.063235.688936.440737.223837.583138.497538.992339.946239.886139.841539.916840.032340.146240.411140.826541.278641.378241.543341.801142.144142.646842.886543.15943.482543.561143.614543.563943.588943.823544.157644.462444.779445.126645.297945.620245.717645.796445.849245.961945.985245.803445.63445.444845.256144.959544.796644.558944.311644.189844.260144.21544.338644.717144.686144.164243.698343.023742.133942.682643.353343.997344.396844.868345.619445.961346.503947.124946.9447.457348.195947.939847.648347.388146.615846.212546.508546.152145.671746.141846.19246.580547.133847.875947.626447.311847.147846.633246.473946.37246.274145.884445.614645.206844.671943.686143.264343.639144.930645.36146.042347.092547.70347.987248.273847.779647.524447.330847.018546.704346.552246.620347.091747.417747.639448.020548.183748.241948.31848.381848.457648.831349.257650.141851.509152.517652.927252.973353.343853.584453.615953.856353.782253.312452.915952.486752.216451.817551.345251.017350.747950.487650.179850.093749.356748.753547.814347.326946.900846.252145.761745.52246.084546.720346.819147.370347.8578484847.593547.283546.667546.322946.490946.758947.279347.403447.296246.818246.037345.362944.040342.938741.28740.565541.761843.159744.799845.499446.931247.894248.581249.155249.233848.751447.824247.421946.755446.446446.356446.626746.876546.735746.043845.717245.485845.356145.221845.064145.142745.298245.54745.885845.925245.892945.933246.012846.11946.137846.057746.004345.921445.883845.71845.527345.468545.480745.508945.548145.285445.042544.739544.425144.311244.320944.360744.458644.573944.355644.186943.614443.175342.816542.822342.968443.291343.665344.14944.544.648145.047545.735645.710245.474345.179544.569944.082143.728943.433343.22643.036143.18143.198943.095742.784743.057144.357945.749246.90347.46447.472947.569347.677747.684947.120745.53945.070344.048243.897643.862243.893343.65843.489843.575543.630443.859243.8543.855143.867943.744143.332742.840742.436142.318842.347842.415542.414943.136943.614144.894145.000645.259245.168644.376643.418442.75943.025242.945342.427642.820843.307243.670543.82143.948543.978943.991743.955443.84144.116244.439444.84645.223945.606245.958845.637644.355943.253542.776942.33941.99241.790641.448441.196641.067940.903240.786840.703240.613740.625241.081441.710742.454343.01542.880842.833742.612642.525942.465442.430442.461142.302541.745241.304340.861540.419540.563740.628141.255641.576942.246942.810343.290143.988144.538645.031845.446845.940646.357846.735346.349345.956745.780245.701145.376945.197145.332945.474345.66145.770745.543845.331945.153245.054245.514946.182746.338946.38146.464247.010147.772348.248848.576848.907148.965949.252549.331749.434449.400749.32149.167249.231749.459549.513449.553450.097950.315650.312650.456150.756851.23251.587952.645753.770155.180356.209656.663256.73356.75556.809556.808855.847354.703853.429552.265351.365851.194751.105851.846352.701153.169653.350153.398253.243953.069452.912153.306353.434354.167454.897255.613356.451557.080457.443158.064558.021757.232555.802254.226153.941554.324754.801155.59556.336957.021957.894457.848457.73157.585757.411757.179857.070256.976957.934258.924659.952959.585658.962258.102957.476356.518655.754654.725453.834653.910953.841853.816854.081553.754453.335652.792352.309452.444252.703952.875752.9952.949252.891752.805952.728153.528654.293555.431156.117255.605555.167554.681954.128154.044354.154954.224554.318754.398954.342254.214154.015454.32454.696554.97955.160455.413955.535555.554655.592455.773855.977855.886955.740655.638455.533655.504855.502755.457955.283455.271955.125154.977454.793454.691755.139555.810556.55857.059557.538257.931457.850857.810457.784157.830757.784157.623756.720256.482556.450556.404856.029955.624755.234755.109155.136155.150355.193755.303955.187454.993154.096552.958552.007851.087850.254149.527449.336349.296349.36749.557649.841349.966350.072150.234350.283350.381750.407450.650351.480151.938452.327752.686353.098653.468953.687153.320852.96552.639252.40152.27252.247652.183952.167752.161752.053252.062752.068752.068352.067152.033852.067452.233852.298352.329152.333152.376451.837451.138850.535549.913849.817749.539549.488749.570749.943250.356650.843851.099951.294951.873352.436252.966552.895552.458452.057451.30850.860450.542550.119449.774649.341248.763748.389348.104648.071448.691249.213349.576150.039850.345650.753251.238951.824152.685253.233653.766553.844553.318452.817852.468551.896751.930551.99451.998651.962251.976552.03752.142552.169452.304752.512752.873953.288453.653153.304852.964152.666452.417752.380352.442352.382452.342652.2252.094152.521252.995553.167953.716454.090654.337254.547554.868255.187855.127355.088154.973454.86755.344555.91556.368556.723455.968155.367354.785254.236353.677653.183552.745252.153651.729351.805451.936252.006651.870251.613251.692851.754951.893951.977952.173352.285152.39452.148451.752651.388950.689750.00349.201748.657248.545947.758947.279146.880246.527146.402246.587346.712446.844646.956847.01147.040947.047547.005147.073147.121347.185447.249547.266146.84446.327545.878645.345845.405845.678846.010746.440947.002547.526848.018348.529849.133449.686549.941550.205150.381450.632950.746550.92151.096651.42751.63251.872352.110351.773951.225350.679950.107550.155750.405750.807451.169751.243451.164951.074151.018551.051851.167851.30151.437351.487151.496351.519251.532951.508151.498451.425351.324451.191250.843950.617950.373650.108649.710449.291549.018348.735648.55848.448748.355548.262148.361148.564248.811149.20449.883450.79351.603252.074552.312552.544352.767752.517552.141251.735851.448251.503251.54951.585651.553351.210250.94750.678250.438550.399850.46250.654150.866851.311351.693952.079452.384852.755953.011653.185453.258753.382353.478453.583753.693153.828653.913653.993653.935353.822153.693153.583253.450453.317753.203253.107153.088852.972852.749352.542252.372552.232152.147552.076552.532353.034753.55354.09354.573655.043755.343255.40255.129554.530954.050353.454253.037152.70552.326652.075252.078552.192552.240552.231852.204352.354352.474852.602952.240551.754851.367950.990650.807950.926951.036751.174151.336351.505951.633351.732651.798251.603351.370251.214851.054651.020551.083851.183751.225251.279751.162751.28651.554651.910852.374652.748852.859852.47552.071751.816151.592451.412551.423651.45151.471651.575451.778351.962951.774951.367250.98750.530650.043349.470549.32150.595952.235953.435254.401155.677156.958257.989657.912157.684457.401457.24156.802556.030155.705555.52455.363655.177255.141255.134355.047554.883354.893655.050555.191555.327455.344755.380755.584455.815256.172256.813956.898456.823556.808456.81756.886956.987357.33957.683657.667657.673357.65557.577157.027856.65756.148955.786655.531655.394355.089255.162955.287755.403255.47555.221454.932354.662954.366954.175754.007153.851753.794553.806153.850353.901353.951753.665553.145252.521951.950652.146852.505752.77353.202253.577353.824253.935754.085754.266254.698255.174155.628955.890456.113556.127556.124256.122156.123956.370556.619856.858357.148957.424157.727157.527757.333557.017256.840656.678456.45856.569757.099657.723358.417458.866659.309659.476659.525659.653859.676659.784459.888859.958759.99360.061160.146360.217760.33660.469360.574760.700660.8360.95861.144361.327761.498561.616261.938162.373862.736963.200863.406663.488763.961764.618865.425966.014366.632967.396268.355368.66168.926869.107769.194269.133669.009368.921668.802268.551568.357768.309268.355668.506268.73268.793866.973464.974662.829760.803259.052357.294156.582256.412756.577556.824757.071957.566357.716458.080658.071558.061557.953557.887757.928958.047958.059658.621259.282159.537660.17760.814861.154961.727162.094762.159562.227662.381962.528162.740962.677562.68562.733962.96963.171563.678964.176664.494864.81665.138465.389765.43465.620565.690165.829265.991466.213666.287366.292766.185766.014165.952165.819365.714165.627165.56365.466965.402865.344465.41465.578565.672665.784165.715565.546365.375665.390465.356765.308765.52365.571965.179964.753364.416764.225564.06663.990263.921963.887563.91664.000264.078963.688862.951562.187861.399861.053661.145161.211761.252261.347960.420359.571258.694858.017757.381656.769556.21155.99455.993555.999156.00355.947855.748255.511955.270355.130955.382155.629755.910656.030956.124456.365356.588556.82856.891856.584756.379756.124555.664355.260854.890354.520954.76555.204355.635155.898456.241356.266856.228456.193556.093256.015155.97555.615155.078754.515853.907453.443453.295253.091852.765952.676652.328852.045351.648751.283150.947251.226851.550851.835452.173451.796151.305650.911150.532350.131149.674349.387949.281249.334649.463449.741749.989150.420950.584150.547550.529250.529250.513850.500150.48550.452550.377150.249150.627150.895151.443452.162152.709853.028553.840754.462355.263355.879855.290154.764854.37254.276853.79753.17752.637551.979451.33351.02550.859951.040151.069951.107751.119151.432751.531751.729151.885352.217752.342752.662353.013653.231253.492453.720253.940354.238154.561354.734554.909755.042655.158755.247155.317554.940354.64954.299753.888653.036752.324552.237352.685353.090553.605354.277754.754954.63154.442254.183854.16454.062954.09953.92153.473252.906852.193551.372950.490149.636848.909148.327847.836647.606147.676348.012848.405748.506548.639448.710448.304548.049947.380246.825646.234446.193545.975545.749945.711645.858446.062846.37346.59246.435645.717245.084544.520544.340644.330844.461444.721844.94445.362245.791745.997946.262546.562846.715546.434945.770344.930544.23843.837944.211544.573245.011545.587246.096446.733347.396148.050749.061349.254149.537349.499449.548650.03350.34450.557649.793248.755547.780847.255247.054746.777546.559446.269445.578144.968844.313543.592843.045742.627942.220242.08842.257542.412542.404442.445942.438542.40542.260542.024241.858541.966142.222942.58642.956143.672944.401344.783945.191345.550145.846846.585747.350548.210148.980950.045950.524950.074649.264748.208747.323747.154746.55946.059745.431645.193645.156345.14845.251945.522945.869645.838845.572745.195844.83144.746344.633544.592144.485844.981145.144444.715344.307143.642243.032942.906642.664242.725842.717841.921341.379840.934840.427440.166339.843539.732539.543739.317739.046738.877938.756238.816439.069939.496640.03540.416341.10841.253941.619941.67941.579841.350340.812640.535640.127639.155938.543439.207939.332539.502139.604939.5639.558439.602139.566839.425339.367738.998138.581538.253138.186637.659837.182437.068737.334937.641637.872738.497338.917939.511840.14440.752241.356941.813442.088842.160942.149542.0341.919941.729441.411341.0240.459740.053339.930639.862239.66639.49639.209539.341839.627939.950640.208740.440440.479240.435940.343740.227140.007239.729339.554739.363438.874338.785138.861738.851738.845238.823338.691239.337839.810240.353140.46440.889341.24741.395141.56842.111942.791643.433943.93344.232544.82645.728846.806647.467148.426748.622548.605548.04547.867846.707846.174545.092745.205144.833944.495544.413544.389644.062343.684643.347643.125843.014443.006842.885842.986843.227443.390343.391543.203843.276143.704844.099144.536544.974444.884244.875544.830744.776644.728744.656844.582344.461344.308344.285644.266743.945643.673543.249442.739842.149841.689441.354141.686142.063542.498543.243.607943.998943.695443.397943.146142.779942.011641.358240.487339.800239.385739.521339.708440.422741.337942.33642.418942.990642.92442.437941.785341.339540.777940.31440.074539.668339.352639.018438.559738.151737.708937.398736.988136.899836.791836.696836.635236.615737.013537.351137.581637.613337.636537.681237.862938.180438.35138.541438.80239.081238.947338.657238.307637.875537.657537.756537.578237.183636.329434.880133.46733.429533.636534.053833.70533.63933.643133.587633.464533.044532.551431.581230.873430.195731.012631.035231.399631.49231.264131.167731.331131.137530.652630.43930.53830.508832.102633.39234.645335.988337.63738.012340.278442.362944.232445.599345.647245.59145.614945.59945.571446.536547.480146.088344.136842.692941.731640.717240.385540.068939.668539.177940.025841.572742.816644.326145.673844.14742.860741.673640.883441.595142.231642.700143.283844.506546.097647.592149.43251.329153.526256.050758.305760.636461.016959.768158.311156.779954.355251.891548.982746.352344.438443.317942.30541.825141.707440.727240.125640.030834.0833.061733.14133.692633.918734.197234.553934.612934.635534.624233.951332.710931.92431.505431.210730.997530.964631.116331.149331.163731.18331.118531.01530.685430.345230.121429.894129.622329.469829.422929.40729.495629.689630.201330.713731.072731.420231.82532.312932.823733.433733.794833.795333.767233.344633.292433.16532.604932.467132.086432.061432.125932.081831.877631.633231.389531.039930.360630.304229.699129.715329.433329.153629.018628.885129.667331.01531.65532.609433.582334.115134.378334.451934.821634.421832.544230.289428.8929.3630.506431.477932.432833.843535.526237.237439.233240.512539.415637.680735.743535.636135.485535.722538.806638.907339.259839.964739.561938.81338.573438.252437.821437.791437.872137.656937.651737.866537.97138.113138.164238.888339.347739.825840.605641.496642.63341.817341.507140.729939.874739.159438.882538.603238.475338.228138.168938.450238.852838.653737.791936.8836.179735.48835.028634.485633.762133.693733.603140.171339.889141.0842.741144.986846.473548.409748.513647.31245.923844.696443.958842.582140.872439.810938.869237.846236.899536.349636.003235.658135.520835.407335.304235.229735.186635.12534.89134.797734.567834.208334.050734.045334.062434.048434.138334.312834.44534.637234.777435.582336.576736.911436.868737.14937.457438.114838.52139.362839.376439.247739.261138.290337.428836.914236.592536.256235.843836.101435.97435.749835.432134.99134.499233.729232.693432.017231.88931.425431.325831.366131.385631.400635.906635.978736.024136.282836.575836.990137.315137.715638.024638.539638.797838.93739.038339.239939.651739.875540.21940.968341.332241.396141.327741.658242.581144.054545.86646.421546.590446.232645.868245.705644.959544.573744.183343.564943.62943.711343.59843.467342.558541.805640.985440.482940.405540.628640.750841.105441.626342.560943.892445.247345.636644.240543.977742.364741.229940.038839.361238.57837.839136.402835.161734.282233.724333.91934.81235.547935.99837.235237.899638.462138.550838.496337.975537.062835.625534.917934.168134.489134.79335.145135.161935.166635.298235.403535.491635.636935.913936.139336.368436.154536.128236.091836.129136.25236.53637.018737.23337.283437.282737.17337.034636.99237.338737.957438.882339.05140.263441.225942.299442.418842.8443.344943.672544.025744.421844.824545.430145.636345.908446.224946.426246.831946.85946.618746.514146.327746.205746.061445.814145.443345.075144.522344.232243.499643.303242.693242.754542.833443.075243.22943.402743.499843.791644.101744.346644.101244.001244.073644.429644.857245.421645.695546.122646.452746.821247.059947.050246.95246.900546.779446.072445.887445.229144.318743.528742.718141.732240.958640.020739.167538.549238.096537.974738.158638.417238.559338.830639.39139.660740.085840.106540.018740.119840.401940.634441.123341.594741.916642.331342.403342.796643.213643.463643.751144.350844.901445.5245.768145.917746.081646.115146.370646.961747.281247.580747.941748.009747.226546.63145.777845.311245.440145.619245.669845.587646.535347.102747.879149.000649.713649.844449.727649.698949.725749.684949.571949.21649.067348.79248.55248.243947.860547.567847.628447.669847.598347.453147.149246.199444.799643.639642.370241.462940.890340.249939.779739.417138.878938.254337.755437.332536.78836.551935.828735.154434.541834.338934.230334.122333.972334.284934.472834.604334.731734.907335.489536.307136.763737.62738.211638.453838.435538.449238.458438.402438.178737.960737.74337.519237.410437.563237.735737.872437.935738.165438.385738.547938.58838.640938.717339.009139.455839.647740.195640.350440.321240.347440.455140.310340.155439.888639.760639.267238.93538.835138.75638.796938.729238.557238.396838.11537.948437.823137.762637.950938.071638.173638.239638.277638.072537.669737.35137.053436.934937.186737.386937.586137.82738.071338.307938.382338.462438.671738.724238.777538.769338.496638.399138.463338.452538.507438.570838.645638.183537.824737.470537.237636.976736.661736.58136.539236.470836.415136.375836.368536.368536.368536.363936.368536.363936.391436.395936.395936.907437.139537.361437.58537.849938.077438.277738.599338.87538.940539.231739.529539.564839.912540.159740.360540.291240.218640.086740.118440.270440.423440.603340.744440.685440.638140.637940.703341.20441.727442.336542.908342.880942.825942.798542.640742.272741.895141.575941.31741.901742.607743.100143.676844.140244.722845.265945.635445.560845.408545.311145.302845.411746.094246.837847.732847.511346.731645.871845.48545.303446.08946.699447.28547.758947.798547.627847.450547.442647.539647.578247.577447.713748.501649.509950.288950.862151.915552.574253.250753.797154.420654.649254.963655.243655.469555.667855.897556.192256.365656.453956.239756.070255.973355.909755.956955.952956.001856.013156.247756.348255.82755.263155.024155.012654.938154.549854.61955.078755.818156.429656.56556.709856.750856.693956.400155.534855.343554.867354.37953.885653.522953.143253.208353.61753.939554.352554.508654.699355.308955.722756.26356.301456.247356.227456.151556.117755.867855.678955.529755.497955.262355.169754.875254.504554.310954.238254.000453.857353.745353.582753.893754.261354.296854.423854.59654.679954.717554.738354.190353.668653.210352.621152.179252.094952.057952.015251.647951.369451.066950.775250.458650.054450.094950.171850.253850.633651.092751.422151.658551.850451.874551.973851.999451.973151.945751.909151.899951.872451.936551.945751.973151.954851.973151.988551.975251.959551.956951.991551.704751.670851.804952.155552.769553.553354.759354.933754.787254.645354.530954.384454.251654.118953.875853.324952.876552.466952.052851.515751.358451.204751.088650.976851.11251.33751.573751.713151.82451.912651.980251.990651.991952.072752.200852.264352.570853.205954.130954.996355.967957.043357.827858.392458.150257.038655.144652.933950.897749.049949.230349.772150.054850.038849.273248.219247.443347.100247.584648.654449.400449.616249.901350.033150.383850.705750.895951.042451.853352.744354.077755.574457.033458.023158.830959.993259.926859.857959.719559.707559.761359.816759.868159.950959.20558.258557.425556.770156.581556.820457.054657.386257.641457.504657.257856.917656.460555.998955.479554.970854.533654.082253.796653.723453.668553.613553.540353.503753.600953.732253.858454.019453.99153.954353.93653.93654.146654.366354.485454.603754.62654.617154.484654.291854.144754.023753.972853.859753.725853.57353.413953.363753.120553.047953.073853.134353.116653.046852.874852.592952.203151.818651.74451.6651.631451.575851.38651.138551.00750.864450.974951.288951.653852.016652.213352.505352.849352.573251.960751.5951.314951.147451.085651.187551.52151.670551.651851.514351.42651.094150.737150.486250.339450.17949.993149.943450.067650.296550.568850.950151.500651.849651.952851.906352.002352.748953.345753.962754.215153.552753.056352.822352.156151.606951.370751.451351.502651.477651.403551.269251.257451.260151.243151.160151.022850.88750.674550.465450.297450.318650.314250.306450.292850.295150.294250.305150.368550.469850.623350.765250.916350.91950.603550.153349.861849.548349.281248.886248.547848.214948.06648.439549.123349.719150.488751.171451.986252.646352.005351.204650.616249.787549.0748.334548.189448.054648.02948.087448.210848.422248.818248.992148.629448.246347.990247.558947.221746.586545.86444.966143.918542.708742.147542.036342.005442.071142.081542.213942.440543.296444.263545.377146.496447.569448.295848.319248.297748.243348.168448.050447.93647.529447.001946.532246.047445.600145.262245.622645.976246.105645.892945.291945.214744.928544.528344.170144.071444.114144.260444.475844.751344.964245.049745.047344.780244.578644.013743.844343.199742.509942.44143.092643.786844.384344.781245.280645.411545.800646.131946.445446.677446.685346.65946.549646.235845.443544.852444.449544.110443.973743.984744.302744.572444.896645.295345.690346.127846.714847.112147.441847.590647.826648.040448.200248.349448.452648.629348.583948.484948.35448.15848.426949.540549.682349.646648.813247.58245.918444.687444.480844.424445.013845.976947.058448.631449.960651.018551.96652.852953.080452.466852.011851.404751.007651.441551.795151.943851.962852.059352.0691 ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.position/src/main/resources/test.gpx ================================================ Track 002 Mar 25, 2010 10:19 am 1602.000000 1605.000000 1606.000000 1608.000000 1608.000000 1607.000000 1607.000000 1607.000000 1608.000000 1609.000000 1610.000000 1610.000000 1610.000000 1609.000000 1609.000000 1609.000000 1610.000000 1611.000000 1611.000000 1611.000000 1612.000000 1613.000000 1614.000000 1614.000000 1614.000000 1613.000000 ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.usb Bundle-SymbolicName: org.eclipse.kura.emulator.usb;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.usb; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: javax.usb;version="1.0.2", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.usb;version="[1.3,1.4)", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/OSGI-INF/usb.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # output.. = target/classes/ source.. = src/main/java/,\ src/main/resources/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ additional.bundles = org.eclipse.osgi,\ slf4j.api,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.usb 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.usb/src/main/java/org/eclipse/kura/emulator/usb/UsbServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.emulator.usb; import java.util.Collections; import java.util.List; import javax.usb.UsbServices; import org.eclipse.kura.KuraException; import org.eclipse.kura.usb.UsbBlockDevice; import org.eclipse.kura.usb.UsbDevice; import org.eclipse.kura.usb.UsbNetDevice; import org.eclipse.kura.usb.UsbService; import org.eclipse.kura.usb.UsbTtyDevice; import org.osgi.service.component.ComponentContext; public class UsbServiceImpl implements UsbService { protected void activate(ComponentContext componentContext) { } protected void deactivate(ComponentContext componentContext) { } @Override public UsbServices getUsbServices() throws KuraException { return null; } @Override public List getUsbDevices() { return Collections.emptyList(); } @Override public List getUsbBlockDevices() { return Collections.emptyList(); } @Override public List getUsbNetDevices() { return Collections.emptyList(); } @Override public List getUsbTtyDevices() { return Collections.emptyList(); } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.emulator.watchdog Bundle-SymbolicName: org.eclipse.kura.emulator.watchdog;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.emulator.watchdog; version="1.0.0" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.watchdog;version="[1.0,1.1)", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/OSGI-INF/metatype/org.eclipse.kura.watchdog.WatchdogService.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/OSGI-INF/watchdog.xml ================================================ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # output.. = target/classes/ source.. = src/main/java/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ about_files/ src.includes = about.html,\ about_files/ ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/pom.xml ================================================ 4.0.0 org.eclipse.kura emulator 6.0.0-SNAPSHOT org.eclipse.kura.emulator.watchdog 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/../.. ${project.basedir}/../../test/org.eclipse.kura.emulator.watchdog.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/src/main/java/org/eclipse/kura/emulator/watchdog/CriticalServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.watchdog; public class CriticalServiceImpl { private final String name; private final long timeout; private long updated; /** * * @param name * @param timeout * timeout for reporting interval in seconds */ public CriticalServiceImpl(String name, long timeout) { this.name = name; this.timeout = timeout; this.updated = System.currentTimeMillis(); } public String getName() { return this.name; } public long getTimeout() { return this.timeout; } public boolean isTimedOut() { long current = System.currentTimeMillis(); return this.timeout < current - this.updated; } public void update() { this.updated = System.currentTimeMillis(); } @Override public String toString() { return "Service Name: " + this.name + ", Timeout(ms): " + this.timeout; } } ================================================ FILE: kura/emulator/org.eclipse.kura.emulator.watchdog/src/main/java/org/eclipse/kura/emulator/watchdog/WatchdogServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.emulator.watchdog; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.watchdog.CriticalComponent; import org.eclipse.kura.watchdog.WatchdogService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class WatchdogServiceImpl implements WatchdogService, ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(WatchdogServiceImpl.class); private static List criticalServiceList; private Map properties; private ScheduledExecutorService executor; private ScheduledFuture future; private int pingInterval = 10000; // milliseconds private boolean configEnabled = false; // initialized in properties, if false -> no watchdog private boolean enabled; protected void activate(ComponentContext componentContext, Map properties) { this.properties = properties; if (properties == null) { logger.debug("activating WatchdogService with null props"); } else { logger.debug("activating WatchdogService with {}", properties.toString()); } criticalServiceList = new ArrayList<>(); this.enabled = false; // clean up if this is not our first run if (this.executor != null) { this.executor.shutdown(); while (!this.executor.isTerminated()) { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.debug(e.getMessage(), e); } } this.executor = null; } this.executor = Executors.newSingleThreadScheduledExecutor(); this.future = this.executor.scheduleAtFixedRate(() -> { Thread.currentThread().setName(getClass().getSimpleName()); if (WatchdogServiceImpl.this.configEnabled) { doWatchdogLoop(); } }, 0, this.pingInterval, TimeUnit.MILLISECONDS); } protected void deactivate(ComponentContext componentContext) { this.executor.shutdown(); while (!this.executor.isTerminated()) { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.debug(e.getMessage(), e); } } this.executor = null; criticalServiceList = null; } public void updated(Map properties) { logger.debug("updated..."); this.properties = properties; if (this.properties != null) { Object enabledVal = this.properties.get("enabled"); if (enabledVal != null) { this.configEnabled = (Boolean) enabledVal; } if (!this.configEnabled) { return; } if (this.properties.get("pingInterval") != null) { this.pingInterval = (Integer) this.properties.get("pingInterval"); if (this.future != null) { this.future.cancel(false); while (!this.future.isDone()) { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.debug(e.getMessage(), e); } } } this.future = this.executor.scheduleAtFixedRate(() -> { Thread.currentThread().setName(getClass().getSimpleName()); if (WatchdogServiceImpl.this.configEnabled) { doWatchdogLoop(); } }, 0, this.pingInterval, TimeUnit.MILLISECONDS); } } } @Override public void startWatchdog() { this.enabled = true; } @Override public void stopWatchdog() { this.enabled = false; } @Override public int getHardwareTimeout() { return 0; } @Override public void registerCriticalComponent(CriticalComponent criticalComponent) { final CriticalServiceImpl service = new CriticalServiceImpl(criticalComponent.getCriticalComponentName(), criticalComponent.getCriticalComponentTimeout()); synchronized (criticalServiceList) { // avoid to add same component twice (eg in case of a package updating) boolean existing = false; for (CriticalServiceImpl csi : criticalServiceList) { if (criticalComponent.getCriticalComponentName().compareTo(csi.getName()) == 0) { existing = true; } } if (!existing) { criticalServiceList.add(service); } } logger.debug("Added {} , with timeout = {}, list contains {} critical services", criticalComponent.getCriticalComponentName(), criticalComponent.getCriticalComponentTimeout(), criticalServiceList.size()); } /** * @deprecated use {@link WatchdogServiceImpl#registerCriticalComponent(CriticalComponent)} */ @Override @Deprecated public void registerCriticalService(CriticalComponent criticalComponent) { registerCriticalComponent(criticalComponent); } @Override public void unregisterCriticalComponent(CriticalComponent criticalComponent) { synchronized (criticalServiceList) { for (int i = 0; i < criticalServiceList.size(); i++) { if (criticalComponent.getCriticalComponentName().compareTo(criticalServiceList.get(i).getName()) == 0) { criticalServiceList.remove(i); logger.debug("Critical service {} removed, {}", criticalComponent.getCriticalComponentName(), System.currentTimeMillis()); } } } } /** * @deprecated use {@link WatchdogServiceImpl#unregisterCriticalComponent(CriticalComponent)} */ @Override @Deprecated public void unregisterCriticalService(CriticalComponent criticalComponent) { unregisterCriticalComponent(criticalComponent); } @Override public List getCriticalComponents() { return null; } @Override public void checkin(CriticalComponent criticalService) { synchronized (criticalServiceList) { for (CriticalServiceImpl csi : criticalServiceList) { if (criticalService.getCriticalComponentName().compareTo(csi.getName()) == 0) { csi.update(); } } } } private void doWatchdogLoop() { if (!this.enabled) { return; } boolean failure = false; // Critical Services synchronized (criticalServiceList) { if (!criticalServiceList.isEmpty()) { for (CriticalServiceImpl csi : criticalServiceList) { if (csi.isTimedOut()) { failure = true; logger.warn("Critical service {} failed -> SYSTEM REBOOT", csi.getName()); } } } } if (!failure) { refreshWatchdog(); } } private void refreshWatchdog() { File f = new File("/dev/watchdog"); if (f.exists()) { try (FileOutputStream fos = new FileOutputStream(f); PrintWriter pw = new PrintWriter(fos);) { pw.write("w"); pw.flush(); fos.getFD().sync(); } catch (IOException e) { logger.info(e.getMessage(), e); } } } public boolean isConfigEnabled() { return this.configEnabled; } public void setConfigEnabled(boolean configEnabled) { this.configEnabled = configEnabled; } } ================================================ FILE: kura/emulator/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT emulator pom ${project.basedir}/.. org.eclipse.kura.emulator org.eclipse.kura.emulator.gpio org.eclipse.kura.emulator.clock org.eclipse.kura.emulator.net org.eclipse.kura.emulator.position org.eclipse.kura.emulator.usb org.eclipse.kura.emulator.watchdog ================================================ FILE: kura/kura-pde-deps/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura kura-pde-deps pom Kura PDE Dependencies org.eclipse.kura org.eclipse.kura.api org.eclipse.kura org.eclipse.kura.camel org.eclipse.kura org.eclipse.kura.camel.cloud.factory org.eclipse.kura org.eclipse.kura.camel.xml org.eclipse.kura org.eclipse.kura.cloud.base.provider org.eclipse.kura org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider org.eclipse.kura org.eclipse.kura.cloudconnection.kapua.mqtt.provider org.eclipse.kura org.eclipse.kura.cloudconnection.raw.mqtt.provider org.eclipse.kura org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider org.eclipse.kura org.eclipse.kura.configuration.change.manager org.eclipse.kura org.eclipse.kura.container.orchestration.provider org.eclipse.kura org.eclipse.kura.container.provider org.eclipse.kura org.eclipse.kura.core org.eclipse.kura org.eclipse.kura.core.certificates org.eclipse.kura org.eclipse.kura.core.cloud.factory org.eclipse.kura org.eclipse.kura.core.comm org.eclipse.kura org.eclipse.kura.core.configuration org.eclipse.kura org.eclipse.kura.core.crypto org.eclipse.kura org.eclipse.kura.core.identity org.eclipse.kura org.eclipse.kura.core.inventory org.eclipse.kura org.eclipse.kura.core.keystore org.eclipse.kura org.eclipse.kura.core.status org.eclipse.kura org.eclipse.kura.core.system org.eclipse.kura org.eclipse.kura.rest.tamper.detection.provider org.eclipse.kura org.eclipse.kura.db.h2db.provider org.eclipse.kura org.eclipse.kura.db.sqlite.provider org.eclipse.kura org.eclipse.kura.driver.block org.eclipse.kura org.eclipse.kura.driver.helper.provider org.eclipse.kura org.eclipse.kura.driver.s7plc.provider org.eclipse.kura org.eclipse.kura.emulator org.eclipse.kura org.eclipse.kura.emulator.clock org.eclipse.kura org.eclipse.kura.emulator.gpio org.eclipse.kura org.eclipse.kura.emulator.net org.eclipse.kura org.eclipse.kura.emulator.position org.eclipse.kura org.eclipse.kura.emulator.usb org.eclipse.kura org.eclipse.kura.emulator.watchdog org.eclipse.kura org.eclipse.kura.event.publisher org.eclipse.kura org.eclipse.kura.http.server.manager org.eclipse.kura org.eclipse.kura.json.marshaller.unmarshaller.provider org.eclipse.kura org.eclipse.kura.linux.clock org.eclipse.kura org.eclipse.kura.linux.usb org.eclipse.kura org.eclipse.kura.linux.usb.aarch64 org.eclipse.kura org.eclipse.kura.linux.usb.x86_64 org.eclipse.kura org.eclipse.kura.linux.watchdog org.eclipse.kura org.eclipse.kura.log.filesystem.provider org.eclipse.kura org.eclipse.kura.misc.cloudcat org.eclipse.kura org.eclipse.kura.protocol.modbus org.eclipse.kura org.eclipse.kura.request.handler.jaxrs org.eclipse.kura org.eclipse.kura.rest.cloudconnection.provider org.eclipse.kura org.eclipse.kura.rest.configuration.provider org.eclipse.kura org.eclipse.kura.rest.identity.provider org.eclipse.kura org.eclipse.kura.rest.inventory.provider org.eclipse.kura org.eclipse.kura.rest.keystore.provider org.eclipse.kura org.eclipse.kura.rest.provider org.eclipse.kura org.eclipse.kura.rest.security.provider org.eclipse.kura org.eclipse.kura.rest.service.listing.provider org.eclipse.kura org.eclipse.kura.rest.system.provider org.eclipse.kura org.eclipse.kura.stress org.eclipse.kura org.eclipse.kura.useradmin.store org.eclipse.kura org.eclipse.kura.util org.eclipse.kura org.eclipse.kura.wire.camel org.eclipse.kura org.eclipse.kura.xml.marshaller.unmarshaller.provider org.eclipse.kura org.eclipse.kura.jul.to.slf4j.configuration org.eclipse.kura org.eclipse.kura.core.testutil org.eclipse.kura org.eclipse.kura.test org.eclipse.kura org.eclipse.kura.util.test.driver ================================================ FILE: kura/org.eclipse.kura.api/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.api Bundle-SymbolicName: org.eclipse.kura.api;singleton:=true Bundle-Version: 3.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura;version="1.7.0", org.eclipse.kura.ai.inference;version="1.1.0", org.eclipse.kura.annotation;version="1.0.0", org.eclipse.kura.asset;version="1.0.0", org.eclipse.kura.audit;version="1.0.0", org.eclipse.kura.bluetooth.le;version="1.3.0", org.eclipse.kura.bluetooth.le.beacon;version="1.1.0", org.eclipse.kura.bluetooth.le.beacon.listener;version="1.0.0", org.eclipse.kura.certificate;version="2.1.0", org.eclipse.kura.certificate.enrollment;version="1.0.0", org.eclipse.kura.channel;version="1.4.0", org.eclipse.kura.channel.listener;version="1.0.0", org.eclipse.kura.clock;version="1.0.1", org.eclipse.kura.cloud;version="1.1.0", org.eclipse.kura.cloud.factory;version="1.1.1", org.eclipse.kura.cloudconnection;version="1.0.0", org.eclipse.kura.cloudconnection.factory;version="1.0.0", org.eclipse.kura.cloudconnection.listener;version="1.0.0", org.eclipse.kura.cloudconnection.message;version="1.0.0", org.eclipse.kura.cloudconnection.publisher;version="1.0.0", org.eclipse.kura.cloudconnection.request;version="1.0.0", org.eclipse.kura.cloudconnection.subscriber;version="1.0.0", org.eclipse.kura.cloudconnection.subscriber.listener;version="1.0.0", org.eclipse.kura.comm;version="1.1.0", org.eclipse.kura.command;version="1.2.0", org.eclipse.kura.configuration;version="1.2.0", org.eclipse.kura.configuration.metatype;version="1.1.0", org.eclipse.kura.connection.listener;version="1.0.0", org.eclipse.kura.container.orchestration;version="1.3.0", org.eclipse.kura.container.orchestration.listener;version="1.0.0", org.eclipse.kura.container.signature;version="1.0.0", org.eclipse.kura.crypto;version="1.4.0", org.eclipse.kura.data;version="1.1.2", org.eclipse.kura.data.listener;version="1.0.1", org.eclipse.kura.data.transport.listener;version="1.0.1", org.eclipse.kura.db;version="2.0.0", org.eclipse.kura.db.keyvalue;version="1.0.0", org.eclipse.kura.deployment.hook;version="1.0.0", org.eclipse.kura.driver;version="1.0.0", org.eclipse.kura.driver.descriptor;version="1.0.0", org.eclipse.kura.executor;version="1.0.0", org.eclipse.kura.gpio;version="1.2.0", org.eclipse.kura.identity;version="1.2.0", org.eclipse.kura.identity.configuration.extension;version="1.0.0", org.eclipse.kura.linux.udev;version="1.0.1", org.eclipse.kura.log;version="1.1.0", org.eclipse.kura.log.listener;version="1.0.0", org.eclipse.kura.marshalling;version="1.1.0", org.eclipse.kura.message;version="1.5.0", org.eclipse.kura.message.store;version="1.0.0", org.eclipse.kura.message.store.provider;version="1.0.0", org.eclipse.kura.net;version="2.7.0", org.eclipse.kura.net.dhcp;version="1.2.0", org.eclipse.kura.net.dns;version="1.2.0", org.eclipse.kura.net.firewall;version="2.1.0", org.eclipse.kura.net.modem;version="2.5.0", org.eclipse.kura.net.route;version="1.1.0", org.eclipse.kura.net.status;version="1.1.0", org.eclipse.kura.net.status.ethernet;version="1.0.0", org.eclipse.kura.net.status.loopback;version="1.0.0", org.eclipse.kura.net.status.modem;version="1.1.0", org.eclipse.kura.net.status.vlan;version="1.0.0", org.eclipse.kura.net.status.wifi;version="1.1.0", org.eclipse.kura.net.vlan;version="1.0.0", org.eclipse.kura.net.wifi;version="2.5.0", org.eclipse.kura.position;version="1.4.0", org.eclipse.kura.security;version="1.3.0", org.eclipse.kura.security.keystore;version="1.2.0", org.eclipse.kura.security.tamper.detection;version="1.0.0", org.eclipse.kura.ssl;version="2.1.0", org.eclipse.kura.status;version="1.0.2", org.eclipse.kura.system;version="1.9.0", org.eclipse.kura.type;version="1.1.0", org.eclipse.kura.usb;version="1.3.0", org.eclipse.kura.watchdog;version="1.0.2", org.eclipse.kura.wire;version="2.0.0", org.eclipse.kura.wire.graph;version="1.0.0", org.eclipse.kura.wire.multiport;version="1.0.0", org.eclipse.kura.wire.store.provider;version="1.0.0" Import-Package: com.google.common.net;version="32.1.0", javax.comm;version="1.2.0", javax.crypto, javax.microedition.io;resolution:=optional, javax.net.ssl, javax.usb;version="1.0.2", org.apache.commons.io.output;version="2.4.0", org.apache.logging.log4j;version="2.8.2", org.bouncycastle.pkcs;version="1.78.1", org.osgi.annotation.versioning;version="[1.0.0,2.0.0)";resolution:=optional, org.osgi.framework;version="[1.5.0,2.0.0)", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.0", org.osgi.service.wireadmin;version="1.0.1", org.osgi.util.measurement;version="1.0.1", org.osgi.util.position;version="1.0.1" Bundle-ActivationPolicy: lazy ================================================ FILE: kura/org.eclipse.kura.api/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.api/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.api/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/,src/main/resources/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ about.html,\ about_files/ additional.bundles = org.eclipse.equinox.io,\ slf4j.api,\ org.eclipse.osgi,\ org.eclipse.osgi.util src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.api/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.api 3.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml biz.aQute.bnd bnd-baseline-maven-plugin ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothBeaconAdvertiserNotAvailable.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothBeaconAdvertiserNotAvailable is raised when the advertiser is not available. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothBeaconAdvertiserNotAvailable extends KuraException { private static final long serialVersionUID = -1243607248475874911L; public KuraBluetoothBeaconAdvertiserNotAvailable(Object argument) { super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, null, argument); } public KuraBluetoothBeaconAdvertiserNotAvailable(Throwable cause, Object argument) { super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothCommandException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothCommandException is raised when a command returns an error. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothCommandException extends KuraException { private static final long serialVersionUID = -5848254103027432830L; public KuraBluetoothCommandException(Object argument) { super(KuraErrorCode.BLE_COMMAND_ERROR, null, argument); } public KuraBluetoothCommandException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_COMMAND_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothConnectionException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothConnectionException is raised when an error is detected during the device connection/disconnection. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothConnectionException extends KuraException { private static final long serialVersionUID = -376745878312274934L; public KuraBluetoothConnectionException(Object argument) { super(KuraErrorCode.BLE_CONNECTION_ERROR, null, argument); } public KuraBluetoothConnectionException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_CONNECTION_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothDiscoveryException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothDiscoveryException is raised when an error is detected during the discovery procedure. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothDiscoveryException extends KuraException { private static final long serialVersionUID = -8567067163835638967L; public KuraBluetoothDiscoveryException(Object argument) { super(KuraErrorCode.BLE_DISCOVERY_ERROR, null, argument); } public KuraBluetoothDiscoveryException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_DISCOVERY_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothIOException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothIOException is raised when an error is detected during IO operations. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothIOException extends KuraException { private static final long serialVersionUID = -2183860317209493405L; public KuraBluetoothIOException(Object argument) { super(KuraErrorCode.BLE_IO_ERROR, null, argument); } public KuraBluetoothIOException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_IO_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothNotificationException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothNotificationException is raised when an error is detected during notification. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothNotificationException extends KuraException { private static final long serialVersionUID = -4188172396128459284L; public KuraBluetoothNotificationException(Object argument) { super(KuraErrorCode.BLE_NOTIFICATION_ERROR, null, argument); } public KuraBluetoothNotificationException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_NOTIFICATION_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothPairException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothPairException is raised when an error is detected during the device pairing. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothPairException extends KuraException { private static final long serialVersionUID = 4156356604467216236L; public KuraBluetoothPairException(Object argument) { super(KuraErrorCode.BLE_PAIR_ERROR, null, argument); } public KuraBluetoothPairException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_PAIR_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothRemoveException.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothRemoveException is raised when an error is detected during removing a device from the system. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public class KuraBluetoothRemoveException extends KuraException { private static final long serialVersionUID = 6080252526631911747L; public KuraBluetoothRemoveException(Object argument) { super(KuraErrorCode.BLE_REMOVE_ERROR, null, argument); } public KuraBluetoothRemoveException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_REMOVE_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraBluetoothResourceNotFoundException.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraBluetoothResourceNotFoundException is raised when a resource is not found. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class KuraBluetoothResourceNotFoundException extends KuraException { private static final long serialVersionUID = -1142491109524317287L; public KuraBluetoothResourceNotFoundException(Object argument) { super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, null, argument); } public KuraBluetoothResourceNotFoundException(Throwable cause, Object argument) { super(KuraErrorCode.BLE_RESOURCE_NOT_FOUND, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraConnectException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraConnectException is raised during connect failures. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraConnectException extends KuraException { private static final long serialVersionUID = 5894832757268538532L; public KuraConnectException(Object argument) { super(KuraErrorCode.CONNECTION_FAILED, null, argument); } public KuraConnectException(Throwable cause, Object argument) { super(KuraErrorCode.CONNECTION_FAILED, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraConnectionStatus.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType @SuppressWarnings("checkstyle:hideUtilityClassConstructor") public class KuraConnectionStatus { /** * initial state for any connection */ public static final int NEVERCONNECTED = -1; /** * attempts have been made to connect to the device, but currently * no connection exists */ public static final int DISCONNECTED = 0; /** * attempting to connect to field device, this is a transient state */ public static final int CONNECTING = 1; /** * a connection to the field device currently exists. A status of * CONNECTED does not assure that requests from or commands to this * field device will succeed. */ public static final int CONNECTED = 2; /** * attempting to disconnect from the field device. Disconnection from * a field device may be delayed while outstanding commands are either * completed or terminated. */ public static final int DISCONNECTING = 3; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraDisconnectException.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraConnectException is raised during disconnection failures. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public class KuraDisconnectException extends KuraException { private static final long serialVersionUID = 52917095245324570L; public KuraDisconnectException(Object argument) { super(KuraErrorCode.DISCONNECTION_FAILED, null, argument); } public KuraDisconnectException(Throwable cause, Object argument) { super(KuraErrorCode.DISCONNECTION_FAILED, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraErrorCode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura; /** * KuraErrorCode holds the enumeration of valid error codes for the exception message. For each defined enum value, a * corresponding message should be defined in the properties bundle named: * KuraExceptionMessagesBundle.properties. * * @since 1.3 * */ public enum KuraErrorCode { /** * Configuration Error: {0} */ CONFIGURATION_ERROR, /** * Error updating Configuration of ConfigurableComponent {0} */ CONFIGURATION_UPDATE, /** * Error rolling back to snapshot. */ CONFIGURATION_ROLLBACK, /** * The configuration attribute {0} is undefined. */ CONFIGURATION_ATTRIBUTE_UNDEFINED, /** * The configuration attribute {0} cannot accept value {1}: {2}. */ CONFIGURATION_ATTRIBUTE_INVALID, /** * The configuration attribute {0} is required and no value has been specified. */ CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, /** * Configuration snapshot {0} was not found. */ CONFIGURATION_SNAPSHOT_NOT_FOUND, /** * Error Taking Snapshot. */ CONFIGURATION_SNAPSHOT_TAKING, /** * Error Listing Snapshots. */ CONFIGURATION_SNAPSHOT_LISTING, /** * Error Loading Snapshot */ CONFIGURATION_SNAPSHOT_LOADING, /** * An internal error occurred. {0} * * @deprecated */ INTERNAL_ERROR, /** * The serial port ha an invalid configuration. {0} */ SERIAL_PORT_INVALID_CONFIGURATION, /** * The serial port does not exist. {0} */ SERIAL_PORT_NOT_EXISTING, /** * The port is in use. {0} */ PORT_IN_USE, /** * The operation succeeded only partially. */ PARTIAL_SUCCESS, /** * The current subject is not authorized to perform this operation. {0} */ SECURITY_EXCEPTION, /** * Not connected. */ NOT_CONNECTED, /** * Timeout occurred while waiting for the operation to complete. */ TIMED_OUT, /** * Connection failed. {0} */ CONNECTION_FAILED, /** * Too many in-flight messages. */ TOO_MANY_INFLIGHT_MESSAGES, /** * Error performing operation on store. {0} */ STORE_ERROR, /** * Error encoding {0}. */ ENCODE_ERROR, /** * Error decoding {0}. */ DECODER_ERROR, /** * Metric {0} is invalid. */ INVALID_METRIC_EXCEPTION, /** * Message or its encoding is invalid. */ INVALID_MESSAGE_EXCEPTION, /** * Operation {0} not supported. */ OPERATION_NOT_SUPPORTED, /** * Device {0} is unavailable. */ UNAVAILABLE_DEVICE, /** * Device {0} is closed. */ CLOSED_DEVICE, /** * Error accessing GPIO resource. {0} */ GPIO_EXCEPTION, /** * Command {0} exited with code {1}. * * @since 1.0.8 */ OS_COMMAND_ERROR, /** * Invalid parameter. {0} * * @since 1.0.8 */ INVALID_PARAMETER, /** * Unable to execute system process {0} * * @since 1.2 */ PROCESS_EXECUTION_ERROR, /** * Error processing subscription for {0} * * @since 1.2 */ SUBSCRIPTION_ERROR, /** * Error during BLE notification. * * @since 1.3 */ BLE_NOTIFICATION_ERROR, /** * Error during BLE connection. * * @since 1.3 */ BLE_CONNECTION_ERROR, /** * Error during BLE pairing. * * @since 1.3 */ BLE_PAIR_ERROR, /** * BLE resource not found. * * @since 1.3 */ BLE_RESOURCE_NOT_FOUND, /** * Error during BLE IO activity. * * @since 1.3 */ BLE_IO_ERROR, /** * Error executing {0} command. * * @since 1.3 */ BLE_COMMAND_ERROR, /** * Error during discovery procedure. * * @since 1.3 */ BLE_DISCOVERY_ERROR, /** * Error during device remove. * * @since 2.0 */ BLE_REMOVE_ERROR, /** * Bad request. * * @since 2.0 */ BAD_REQUEST, /** * Not found. * * @since 2.0 */ NOT_FOUND, /** * Service unavailable. {0}. * * @since 2.0 */ SERVICE_UNAVAILABLE, /** * Disconnection failed. * * @since 2.0 */ DISCONNECTION_FAILED, /** * Error during IO operation. * * @since 2.2 */ IO_ERROR, /** * Modem unsupported. * * @since 2.3 */ UNSUPPORTED_MODEM, /** * Certificate invalid. * * @since 2.4 */ INVALID_CERTIFICATE_EXCEPTION } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.osgi.annotation.versioning.ProviderType; /** * The {@link KuraException} class is the superclass of all errors and exceptions in the Kura project. It extends the * JDK {@link Exception} class by requesting its invokers to provide an error code when building its instances. The code * is one value of {@link KuraErrorCode}; the code is used to document the possible error conditions generated by the * platform as well as to identify the localized exception messages to be reported. Exceptions messages are stored in * the {@code KuraExceptionMessagesBundle} Properties Bundle and they are keyed on the exception code. * * @see KuraErrorCode * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraException extends Exception { /** The Constant denoting resource bundle. */ private static final String KURA_EXCEPTION_MESSAGES_BUNDLE = "org.eclipse.kura.core.messages.KuraExceptionMessagesBundle"; /** The Constant denoting message pattern. */ private static final String KURA_GENERIC_MESSAGES_PATTERN = "Generic Error - {0}: {1}"; /** The Logger. */ private static final Logger logger = LogManager.getLogger(KuraException.class); /** The Constant denoting serial version identifier. */ private static final long serialVersionUID = 7468633737373095296L; /** The associated arguments. */ private Object[] arguments; /** The associated error code. */ private final KuraErrorCode code; /** * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}. * * @param code * the error code */ public KuraException(final KuraErrorCode code) { this.code = code; } /** * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}. * * @param code * the error code * @param arguments * the arguments */ public KuraException(final KuraErrorCode code, final Object... arguments) { this.code = code; this.arguments = arguments; } /** * Builds a new {@link KuraException} instance based on the supplied {@link KuraErrorCode}, an optional Throwable * cause, and optional arguments for the associated exception message. * * @param code * the error code * @param cause * the cause * @param arguments * the arguments */ public KuraException(final KuraErrorCode code, final Throwable cause, final Object... arguments) { super(cause); this.code = code; this.arguments = arguments; } /** * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing * only a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is not * meaningful at all for exception translations. That is why, the use of this method is highly discouraged. * Hence, the advised way to construct a {@link KuraException} is to use its constructor with a proper * {@link KuraErrorCode}. * * @param message * the message * @return the kura exception */ public static KuraException internalError(final String message) { return new KuraException(KuraErrorCode.INTERNAL_ERROR, null, message); } /** * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing a * cause and a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is * not meaningful at all for exception translations. That is why, the use of this method is highly * discouraged. Hence, the advised way to construct a {@link KuraException} is to use its constructor with a * proper {@link KuraErrorCode}. * * @param cause * the cause * @return the kura exception */ public static KuraException internalError(final Throwable cause) { return new KuraException(KuraErrorCode.INTERNAL_ERROR, cause, ""); } /** * Factory method to build an {@link KuraException} with the {@link KuraErrorCode#INTERNAL_ERROR} code providing a * cause and a message. This method internally sets the error code to {@link KuraErrorCode#INTERNAL_ERROR} which is * not meaningful at all for exception translations. That is why, the use of this method is highly * discouraged. Hence, the advised way to construct a {@link KuraException} is to use its constructor with a * proper {@link KuraErrorCode}. * * @param cause * the cause * @param message * the message * @return the kura exception */ public static KuraException internalError(final Throwable cause, final String message) { return new KuraException(KuraErrorCode.INTERNAL_ERROR, cause, message); } /** * Gets the error code. * * @return the error code */ public KuraErrorCode getCode() { return this.code; } /** {@inheritDoc} */ @Override public String getLocalizedMessage() { return getLocalizedMessage(Locale.getDefault()); } /** * Gets the localized message. * * @param locale * the locale * @return the localized message */ private String getLocalizedMessage(final Locale locale) { final String pattern = getMessagePattern(locale, this.code); if (this.code == null || KuraErrorCode.INTERNAL_ERROR.equals(this.code)) { if (this.arguments != null && this.arguments.length > 1) { // append all arguments into a single one final StringBuilder sbAllArgs = new StringBuilder(); for (final Object arg : this.arguments) { sbAllArgs.append(" - "); sbAllArgs.append(arg); } this.arguments = new Object[] { sbAllArgs.toString() }; } } return MessageFormat.format(pattern, this.arguments); } /** {@inheritDoc} */ @Override public String getMessage() { return getLocalizedMessage(Locale.US); } /** * Gets the message pattern. * * @param locale * the locale * @param code * the code * @return the message pattern */ private String getMessagePattern(final Locale locale, final KuraErrorCode code) { // Load the message pattern from the bundle String messagePattern = null; ResourceBundle resourceBundle = null; try { resourceBundle = ResourceBundle.getBundle(KURA_EXCEPTION_MESSAGES_BUNDLE, locale); if (resourceBundle != null && code != null) { messagePattern = resourceBundle.getString(code.name()); if (messagePattern == null) { logger.warn("Could not find Exception Messages for Locale {} and code {}", locale, code); } } } catch (final MissingResourceException mre) { // log the failure to load a message bundle logger.warn("Could not load Exception Messages Bundle for Locale {}", locale); } // If no bundle or code in the bundle is found, use a generic message if (messagePattern == null) { if (code != null) { // build a generic message format messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, code.name()); } else { // build a generic message format messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, "Unknown"); } } return messagePattern; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraIOException.java ================================================ /******************************************************************************* * Copyright (c) 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraIOException is raised when an IO failure is detected. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public class KuraIOException extends KuraException { private static final long serialVersionUID = 4440807883112997377L; public KuraIOException(Object argument) { super(KuraErrorCode.IO_ERROR, null, argument); } public KuraIOException(Throwable cause, Object argument) { super(KuraErrorCode.IO_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraInvalidMessageException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraInvalidMessageException extends KuraRuntimeException { private static final long serialVersionUID = -3636897647706575102L; public KuraInvalidMessageException(Object argument) { super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, argument); } public KuraInvalidMessageException(Throwable cause) { super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, cause); } public KuraInvalidMessageException(Throwable cause, Object argument) { super(KuraErrorCode.INVALID_MESSAGE_EXCEPTION, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraInvalidMetricTypeException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraInvalidMetricTypeException extends KuraRuntimeException { private static final long serialVersionUID = 3811194468467381264L; public KuraInvalidMetricTypeException(Object argument) { super(KuraErrorCode.INVALID_METRIC_EXCEPTION, argument); } public KuraInvalidMetricTypeException(Throwable cause, Object argument) { super(KuraErrorCode.INVALID_METRIC_EXCEPTION, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraNotConnectedException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraNotConnectedException is raised when the attempted operation requires * an active connection to the remote server while the current state is * disconnected. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraNotConnectedException extends KuraException { private static final long serialVersionUID = 5894832757268538532L; public KuraNotConnectedException(Object argument) { super(KuraErrorCode.NOT_CONNECTED, null, argument); } public KuraNotConnectedException(Throwable cause, Object argument) { super(KuraErrorCode.NOT_CONNECTED, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraPartialSuccessException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * KuraPartialSuccessException is used capture the response * of bulk operations which allow for the failures of some * of their steps. * KuraPartialSuccessException.getCauses() will return the * exceptions collected during operations for those steps * that failed. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraPartialSuccessException extends KuraException { private static final long serialVersionUID = -350563041335590477L; private final List causes; public KuraPartialSuccessException(String message, List causes) { super(KuraErrorCode.PARTIAL_SUCCESS, (Throwable) null, message); this.causes = causes; } /** * Returns the list of failures collected during the execution of the bulk operation. * * @return causes */ public List getCauses() { return this.causes; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraProcessExecutionErrorException.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraProcessExecutionErrorException is raised when a command/process execution fails. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public class KuraProcessExecutionErrorException extends KuraException { private static final long serialVersionUID = 5091705219678526443L; public KuraProcessExecutionErrorException(Object argument) { super(KuraErrorCode.PROCESS_EXECUTION_ERROR, null, argument); } public KuraProcessExecutionErrorException(Throwable cause, Object argument) { super(KuraErrorCode.PROCESS_EXECUTION_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraRuntimeException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import java.text.MessageFormat; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.osgi.annotation.versioning.ProviderType; /** * The {@link KuraRuntimeException} class is the superclass of all runtime exceptions in the Kura project. It extends * the JDK {@link RuntimeException} class by requesting its invokers to provide an error code when building its * instances. The code is one value of {@link KuraErrorCode}; the code is used to document the possible error conditions * generated by the platform as well as to identify the localized exception messages to be reported. Exceptions messages * are stored in the {@code KuraExceptionMessagesBundle} Properties Bundle and they are keyed on the exception code. * * @see KuraErrorCode * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraRuntimeException extends RuntimeException { /** The Constant denoting resource bundle. */ private static final String KURA_EXCEPTION_MESSAGES_BUNDLE = "org.eclipse.kura.core.messages.KuraExceptionMessagesBundle"; /** The Constant denoting message pattern. */ private static final String KURA_GENERIC_MESSAGES_PATTERN = "Generic Error - {0}: {1}"; /** The Logger. */ private static final Logger logger = LogManager.getLogger(KuraRuntimeException.class); /** The Constant denoting serial version identifier. */ private static final long serialVersionUID = -7202805328805688329L; /** The associated arguments. */ private Object[] arguments; /** The associated error code. */ private final KuraErrorCode code; /** * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}. * * @param code * the error code */ public KuraRuntimeException(final KuraErrorCode code) { this.code = code; } /** * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}. * * @param code * the error code * @param arguments * the arguments */ public KuraRuntimeException(final KuraErrorCode code, final Object... arguments) { this.code = code; this.arguments = arguments; } /** * Builds a new {@link KuraRuntimeException} instance based on the supplied {@link KuraErrorCode}, an optional * Throwable cause, and optional arguments for the associated exception message. * * @param code * the error code * @param cause * the cause * @param arguments * the arguments */ public KuraRuntimeException(final KuraErrorCode code, final Throwable cause, final Object... arguments) { super(cause); this.code = code; this.arguments = arguments; } /** * Gets the error code. * * @return the error code */ public KuraErrorCode getCode() { return this.code; } /** {@inheritDoc} */ @Override public String getLocalizedMessage() { return getLocalizedMessage(Locale.getDefault()); } /** * Gets the localized message. * * @param locale * the locale * @return the localized message */ private String getLocalizedMessage(final Locale locale) { final String pattern = getMessagePattern(locale, this.code); if (this.code == null || KuraErrorCode.INTERNAL_ERROR.equals(this.code)) { if (this.arguments != null && this.arguments.length > 1) { // append all arguments into a single one final StringBuilder sbAllArgs = new StringBuilder(); for (final Object arg : this.arguments) { sbAllArgs.append(" - "); sbAllArgs.append(arg); } this.arguments = new Object[] { sbAllArgs.toString() }; } } return MessageFormat.format(pattern, this.arguments); } /** {@inheritDoc} */ @Override public String getMessage() { return getLocalizedMessage(Locale.US); } /** * Gets the message pattern. * * @param locale * the locale * @param code * the code * @return the message pattern */ private String getMessagePattern(final Locale locale, final KuraErrorCode code) { // Load the message pattern from the bundle String messagePattern = null; ResourceBundle resourceBundle = null; try { resourceBundle = ResourceBundle.getBundle(KURA_EXCEPTION_MESSAGES_BUNDLE, locale); if (resourceBundle != null && code != null) { messagePattern = resourceBundle.getString(code.name()); if (messagePattern == null) { logger.warn("Could not find Exception Messages for Locale {} and code {}", locale, code); } } } catch (final MissingResourceException mre) { // log the failure to load a message bundle logger.warn("Could not load Exception Messages Bundle for Locale {}", locale); } // If no bundle or code in the bundle is found, use a generic message if (messagePattern == null) { if (code != null) { // build a generic message format messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, code.name()); } else { // build a generic message format messagePattern = MessageFormat.format(KURA_GENERIC_MESSAGES_PATTERN, "Unknown"); } } return messagePattern; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraStoreCapacityReachedException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraStoreCapacityReachedException is raised when a message can not be appended * to the publishing queue as the internal database buffer has reached its * capacity for messages that are not yet published or they are still in transit. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraStoreCapacityReachedException extends KuraStoreException { private static final long serialVersionUID = 2622483579047285733L; public KuraStoreCapacityReachedException(Object argument) { super(argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraStoreException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraStoreException is raised when a failure occurred during a persistence operation. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraStoreException extends KuraException { private static final long serialVersionUID = -3405089623687223551L; public KuraStoreException(Object argument) { super(KuraErrorCode.STORE_ERROR, null, argument); } public KuraStoreException(Throwable cause, Object argument) { super(KuraErrorCode.STORE_ERROR, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraTimeoutException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraTimeoutException is raised when the attempted operation failed to respond before the timeout exprises. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraTimeoutException extends KuraException { private static final long serialVersionUID = -3042470573773974746L; public KuraTimeoutException(String message) { super(KuraErrorCode.TIMED_OUT, null, message); } public KuraTimeoutException(String message, Throwable cause) { super(KuraErrorCode.TIMED_OUT, cause, message); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraTooManyInflightMessagesException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraTooManyInflightMessagesException is raised if a publish is attempted when there are already too many messages * queued for publishing. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraTooManyInflightMessagesException extends KuraException { private static final long serialVersionUID = 8759879149959567323L; public KuraTooManyInflightMessagesException(Object argument) { super(KuraErrorCode.TOO_MANY_INFLIGHT_MESSAGES, null, argument); } public KuraTooManyInflightMessagesException(Throwable cause, Object argument) { super(KuraErrorCode.TOO_MANY_INFLIGHT_MESSAGES, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/KuraUnsupportedModemException.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura; import org.osgi.annotation.versioning.ProviderType; /** * KuraUnsupportedModemException is raised when a modem of unknown type is attached. * * @noextend This class is not intended to be subclassed by clients. * @since 2.3 */ @ProviderType public class KuraUnsupportedModemException extends KuraException { private static final long serialVersionUID = -8851093400895948523L; public KuraUnsupportedModemException(Object argument) { super(KuraErrorCode.UNSUPPORTED_MODEM, null, argument); } public KuraUnsupportedModemException(Throwable cause, Object argument) { super(KuraErrorCode.UNSUPPORTED_MODEM, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/InferenceEngineMetricsService.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import java.util.Map; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * * The InferenceEngineMetricsService interface provides APIs to get performance * and status metrics from an Inference Engine. * * @noimplement This interface is not intended to be implemented by clients. * @since 3.0 */ @ProviderType public interface InferenceEngineMetricsService extends InferenceEngineService { /** * Retrieve the performance and status metrics from the Inference Engine * as a map of key-value pairs. Typically the keys are the names of the metrics. * * @return a Map containing the metrics. The key of the entries are the metric names. * @throws KuraException */ public Map getMetrics() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/InferenceEngineService.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * An Inference Engine is a library or a server that accepts multiple files * describing an Artificial Intelligence and Machine Learning models * and allows to perform inference on data. * * The InferenceEngineService interface is a service API for managing an Inference Engine. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.3 */ @ProviderType public interface InferenceEngineService { /** * Run an inference for the given model and inputs. * The input and output type and size must match the * ones in the provided {@link ModelInfo}. * * This will fail if the model is not loaded or the engine is not ready. * * @param modelInfo * the {@link ModelInfo} of the model to be used * @param inputData * a list of input {@link Tensor} * @return a list of output {@link Tensor} * @throws KuraIOException */ public List infer(ModelInfo modelInfo, List inputData) throws KuraException; /** * Load the given model in the inference engine. * If the path of the file containing the model is not provided, * the engine will load it from a standard location in the filesystem. * * @param modelName * the name of the model * @param model * an optional String representing the path on the filesystem where the model is stored * @throws KuraIOException */ public void loadModel(String modelName, Optional modelPath) throws KuraException; /** * Remove a model from the inference engine * * @param modelName * the name of the model * @throws KuraIOException */ public void unloadModel(String modelName) throws KuraException; /** * Return true if the model is loaded and ready * * @param modelName * the name of the model * @throws KuraIOException */ public boolean isModelLoaded(String modelName) throws KuraException; /* * Return the names of the available models * * @return a List of model names * * @throws KuraIOException */ public List getModelNames() throws KuraException; /** * Return informations about a specified model * * @return a {@link ModelInfo} that describes a model * @throws KuraIOException */ public Optional getModelInfo(String modelName) throws KuraException; /** * Check if the inference engine is ready for inferencing * * @return true if the server is ready * @throws KuraIOException */ public boolean isEngineReady() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/ModelInfo.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The ModelInfo class represents the metadata of a model * for Artificial Intelligence and Machine Learning algorithms * * @since 2.3 */ @ProviderType public class ModelInfo { private final String name; private final Optional platform; private final Optional version; private final Map parameters; private final List inputDescriptors; private final List outputDescriptors; /** * Instantiates a new ModelInfo * * @param modelName * the name of the model * @param platform * an optional string representing the model platform * @param version * an optional string representing the model version * @param parameters * a map containing the model parameters. It can be empty. * @param inputDescriptors * a list of {@link TensorDescriptor} of the input tensors * @param outputDescriptors * a list of {@link TensorDescriptor} of the output tensors */ protected ModelInfo(String modelName, Optional platform, Optional version, Map parameters, List inputDescriptors, List outputDescriptors) { this.name = modelName; this.platform = platform; this.version = version; this.parameters = Collections.unmodifiableMap(parameters); this.inputDescriptors = Collections.unmodifiableList(inputDescriptors); this.outputDescriptors = Collections.unmodifiableList(outputDescriptors); } /** * Instantiates a builder for a {@link ModelInfo} * * @param name * the name of the model * @return a {@link ModelInfoBuilder} */ public static ModelInfoBuilder builder(String name) { return new ModelInfoBuilder(name); } /** * Creates a new {@link ModelInfoBuilder} and initializes it from this {@link ModelInfo} instance. * * @return a new {@link ModelInfoBuilder} */ public ModelInfoBuilder toBuilder() { return ModelInfoBuilder.fromModelInfo(this); } /** * Return the name of the model * * @return a string representing the model name */ public String getName() { return this.name; } /** * Return the platform used for running this model * * @return an optional string representing the model platform */ public Optional getPlatform() { return this.platform; } /** * Return the version of the model * * @return an optional string representing the version of the model */ public Optional getVersion() { return this.version; } /** * Return the optional parameters assigned to the model * * @return an unmodifiable map containing the model parameters */ public Map getParameters() { return this.parameters; } /** * Return the descriptors of the input tensors * * @return an unmodifiable list of {@link TensorDescriptor} of the input tensors */ public List getInputs() { return this.inputDescriptors; } /** * Return the descriptors of the output tensors * * @return an unmodifiable list of {@link TensorDescriptor} of the output tensors */ public List getOutputs() { return this.outputDescriptors; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/ModelInfoBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The ModelInfoBuilder class is a builder of {@link ModelInfo} * * @since 2.3 */ @ProviderType public class ModelInfoBuilder { private final String name; private Optional platform; private Optional version; private final Map parameters; private final List inputDescriptors; private final List outputDescriptors; ModelInfoBuilder(String name) { this.name = name; this.platform = Optional.empty(); this.version = Optional.empty(); this.parameters = new HashMap<>(); this.inputDescriptors = new ArrayList<>(); this.outputDescriptors = new ArrayList<>(); } /** * Instantiates a builder for a {@link ModelInfo} and initialises it from the supplied argument. * * @param modelInfo * @return a {@link ModelInfoBuilder} */ public static ModelInfoBuilder fromModelInfo(ModelInfo modelInfo) { ModelInfoBuilder builder = new ModelInfoBuilder(modelInfo.getName()); builder.parameters.putAll(modelInfo.getParameters()); builder.inputDescriptors.addAll(modelInfo.getInputs()); builder.outputDescriptors.addAll(modelInfo.getOutputs()); builder.platform = modelInfo.getPlatform(); builder.version = modelInfo.getVersion(); return builder; } /** * Set the model platform * * @param platform * a string representing the platform used for running the model * @return a ModelInfoBuilder */ public ModelInfoBuilder platform(String platform) { if (nonNull(platform) && !platform.isEmpty()) { this.platform = Optional.of(platform); } return this; } /** * Set the version of the model * * @param version * a string representing the version of the model * @return a ModelInfoBuilder */ public ModelInfoBuilder version(String version) { if (nonNull(version) && !version.isEmpty()) { this.version = Optional.of(version); } return this; } /** * Add a parameter to the model * * @param name * the name of the parameter * @param parameter * an Object representing the value of the parameter * @return a ModelInfoBuilder */ public ModelInfoBuilder addParameter(String name, Object parameter) { this.parameters.put(name, parameter); return this; } /** * Remove a parameter from the model * * @param name * the name of the parameter * @return a ModelInfoBuilder */ public ModelInfoBuilder removeParameter(String name) { this.parameters.remove(name); return this; } /** * Add a descriptor of an input tensor * * @param inputDescriptor * a {@link TensorDescriptor} for the input tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder addInputDescriptor(TensorDescriptor inputDescriptor) { this.inputDescriptors.add(inputDescriptor); return this; } /** * Add a descriptor list of an input tensor * * @param inputDescriptors * a List of {@link TensorDescriptor} for the input tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder addAllInputDescriptor(List inputDescriptors) { this.inputDescriptors.addAll(inputDescriptors); return this; } /** * Remove a descriptor from the input tensor list * * @param inputDescriptor * a {@link TensorDescriptor} for the input tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder removeInputDescriptor(TensorDescriptor inputDescriptor) { this.inputDescriptors.remove(inputDescriptor); return this; } /** * Add a descriptor of an output tensor * * @param outputDescriptor * a {@link TensorDescriptor} for the output tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder addOutputDescriptor(TensorDescriptor outputDescriptor) { this.outputDescriptors.add(outputDescriptor); return this; } /** * Add a descriptor list of an output tensor * * @param outputDescriptors * a List of {@link TensorDescriptor} for the output tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder addAllOutputDescriptor(List outputDescriptors) { this.outputDescriptors.addAll(outputDescriptors); return this; } /** * Remove a descriptor from the output tensor list * * @param ioututDescriptor * a {@link TensorDescriptor} for the input tensor * @return a ModelInfoBuilder */ public ModelInfoBuilder removeOutputDescriptor(TensorDescriptor outputDescriptor) { this.outputDescriptors.remove(outputDescriptor); return this; } /** * Create an instance of ModelInfo * * @return a {@ModelInfo} */ public ModelInfo build() { if (isNull(this.name) || this.name.isEmpty()) { throw new IllegalArgumentException("The name of the model cannot be empty or null"); } if (this.inputDescriptors.isEmpty()) { throw new IllegalArgumentException("The input descriptors list cannot be empty"); } if (this.outputDescriptors.isEmpty()) { throw new IllegalArgumentException("The output descriptors list cannot be empty"); } return new ModelInfo(this.name, this.platform, this.version, this.parameters, this.inputDescriptors, this.outputDescriptors); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/Tensor.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import java.util.List; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The Tensor class represents the input or output of a model * for Artificial Intelligence and Machine Learning algorithms * * @since 2.3 */ @ProviderType public class Tensor { private final TensorDescriptor descriptor; private final Class type; private final List data; /** * Instantiates a Tensor * * @param type * the type of tensor data as Java class * @param descriptor * the {@link TensorDescriptor} of this tensor * @param data * the list of data of this tensor */ public Tensor(Class type, TensorDescriptor descriptor, List data) { this.type = type; this.descriptor = descriptor; this.data = data; } /** * Return the descriptor of the tensor * * @return the {@link TensorDescriptor} of the tensor */ public TensorDescriptor getDescriptor() { return this.descriptor; } /** * Return the data contained in the tensor * * @param type * the type of the data as Java class. The type argument must match the type of the tensor. * @return a list of data of the given type */ @SuppressWarnings("unchecked") public Optional> getData(Class type) { if (this.type == type) { return Optional.of((List) this.data); } else { return Optional.empty(); } } /** * Return the type of the tensor * * @return the {@link Class} of the data contained in the tensor */ public Class getType() { return this.type; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/TensorDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The TensorDescriptor class describes the {@link Tensor} used as input or output * of a model for Artificial Intelligence and Machine Learning algorithms * * @since 2.3 */ @ProviderType public class TensorDescriptor { private final String name; private final String type; private final Optional format; private final List shape; private final Map parameters; /** * Instantiates a tensor descriptor * * @param name * the name of the tensor * @param type * a string representing the type of data contained in the tensor. * Its value is implementation specific, so a user should refer to * the implementation documentation to figure out the allowed values. * @param shape * the shape of the data */ public TensorDescriptor(String name, String type, Optional format, List shape, Map parameters) { this.name = name; this.type = type; this.format = format; this.shape = Collections.unmodifiableList(shape); this.parameters = Collections.unmodifiableMap(parameters); } /** * Instantiates a builder for a {@link TensorDescriptor} * * @param name * the name of the tensor * @param type * a string representing the type of data contained in the tensor. * Its value is implementation specific, so a user should refer to * the implementation documentation to figure out the allowed values. * @param shape * the shape of the data as the size of a multi-dimensional matrix */ public static TensorDescriptorBuilder builder(String name, String type, List shape) { return new TensorDescriptorBuilder(name, type, shape); } /** * Creates a new {@link TensorDescriptorBuilder} and initialises it from this {@link TensorDescriptor} instance. * * @return a new {@link TensorDescriptorBuilder} */ public TensorDescriptorBuilder toBuilder() { return TensorDescriptorBuilder.fromTensorDescriptor(this); } /** * Return the name of the tensor * * @return a string representing the tensor name */ public String getName() { return this.name; } /** * Return the type of data contained in the tensor. * Its value is implementation specific, so a user should refer to * the implementation documentation to figure out the allowed values. * * @return a string representing the type of data contained in the tensor */ public String getType() { return this.type; } /** * Return the format of the data. * It represents how the data are organised or grouped in the tensor. * Its value is implementation specific, so a user should refer to * the implementation documentation to figure out the allowed values. * * @return an optional string representing the format of the data in the tensor */ public Optional getFormat() { return this.format; } /** * Return the shape of the data as the size of a multi-dimensional matrix. * * @return an unmodifiable list of longs representing the shape of the data */ public List getShape() { return this.shape; } /** * Return the optional parameters assign to the tensor * * @return an unmodifiable map containing the tensor parameters */ public Map getParameters() { return this.parameters; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ai/inference/TensorDescriptorBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ai.inference; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The TensorDescriptorBuilder class is a builder of {@link TensorDescriptor} * * @since 2.3 */ @ProviderType public class TensorDescriptorBuilder { private final String name; private final String type; private Optional format; private final List shape; private final Map parameters; TensorDescriptorBuilder(String name, String type, List shape) { this.name = name; this.type = type; this.format = Optional.empty(); this.shape = shape; this.parameters = new HashMap<>(); } /** * Instantiates a builder for a {@link TensorDescriptor} and initialises it from the supplied argument. * * @param descriptor * @return a {@link TensorDescriptorBuilder}. */ public static TensorDescriptorBuilder fromTensorDescriptor(TensorDescriptor descriptor) { final TensorDescriptorBuilder result = new TensorDescriptorBuilder(descriptor.getName(), descriptor.getType(), descriptor.getShape()); result.parameters.putAll(descriptor.getParameters()); result.format = descriptor.getFormat(); return result; } /** * Set the format of the data contained in the tensor. * It represents how the data are organised or grouped in the tensor * (e.g. in row-major or column-major order). * Its value is implementation specific, so a user should refer to * the implementation documentation to figure out the allowed values. * * @param format * a string representing the format of the data in the tensor * @return a TensorDescriptorBuilder */ public TensorDescriptorBuilder format(String format) { if (nonNull(format) && !format.isEmpty()) { this.format = Optional.of(format); } return this; } /** * Add a parameter to the tensor descriptor * * @param name * the name of the parameter * @param parameter * an Object representing the value of the parameter * @return a TensorDescriptorBuilder */ public TensorDescriptorBuilder addParameter(String name, Object parameter) { this.parameters.put(name, parameter); return this; } /** * Remove a parameter from the tensor descriptor * * @param name * the name of the parameter * @return a TensorDescriptorBuilder */ public TensorDescriptorBuilder removeParameter(String name) { this.parameters.remove(name); return this; } /** * Create an instance of TensorDescriptor * * @return a {TensorDescriptor} */ public TensorDescriptor build() { if (isNull(this.name) || this.name.isEmpty()) { throw new IllegalArgumentException("The name of the tensor cannot be empty or null"); } if (isNull(this.type) || this.type.isEmpty()) { throw new IllegalArgumentException("The type of the tensor cannot be empty or null"); } if (isNull(this.shape) || this.shape.isEmpty()) { throw new IllegalArgumentException("The shape of the tensor cannot be empty or null"); } return new TensorDescriptor(this.name, this.type, this.format, this.shape, this.parameters); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Extensible.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * This annotation denotes that the annotated type can be extended by others for * special purpose functionalities * * @since 1.2 */ @Target(TYPE) @Retention(RUNTIME) @Documented public @interface Extensible { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Immutable.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * This annotation denotes that the annotated type is immutable and eventually * it becomes thread-safe. By definition, a class is considered to be an * immutable class in which the state of its instance cannot be observed * to be changed. So, inherently this implies that, *
    *
  • All of its public fields must be declared as {@code final}
  • *
  • All of its public final reference fields are either {@code null} or refer * to other immutable objects
  • *
  • Constructors and methods do not contain references to any potentially * mutable internal state.
  • *
*

* In addition, the immutable objects are inherently thread-safe and that is the * reason, they can be passed between threads or published without explicit * synchronization or locks. * * @since 1.2 */ @Documented @Target(TYPE) @Retention(RUNTIME) public @interface Immutable { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/NotThreadSafe.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * This annotation denotes that the annotated type is not thread-safe. On the * contrary, if any type is not annotated with this annotation, does not * necessarily indicate that the type in consideration is thread-safe. The * motive of this annotation is to inform consumers of the annotated type that * consumers must not make any abrupt assumption that the type is thread-safe. * If the author of the type believes that the consumer can make such * assumptions of thread-safety for types even though the types are not, it is * better to annotate the type with this annotation. * * @since 1.2 */ @Documented @Target(TYPE) @Retention(RUNTIME) public @interface NotThreadSafe { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/Nullable.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.annotation; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.CLASS; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * The existence of this annotation indicates that the author believes that the * annotated field or method or parameter or local variable can accept null * values * * @since 1.2 */ @Documented @Target({ FIELD, METHOD, PARAMETER, LOCAL_VARIABLE }) @Retention(CLASS) public @interface Nullable { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/ThreadSafe.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.annotation; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; /** * This annotation denotes that the annotated type is thread-safe. This * inherently means that there should not be any sequence of operations followed * which could potentially render the instance of the annotated type into an * invalid state. * * @since 1.2 */ @Documented @Target(TYPE) @Retention(RUNTIME) public @interface ThreadSafe { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/annotation/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides all necessary annotations required for Kura * * @since 1.0.10 */ package org.eclipse.kura.annotation; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/Asset.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.asset; import java.util.List; import java.util.Set; import org.eclipse.kura.KuraException; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.channel.listener.ChannelListener; import org.osgi.annotation.versioning.ProviderType; /** * This interface Asset provides higher level abstraction to operate or * perform actions on the industrial device. This actually propagates the * necessary operations to the associated device driver. The asset exposes the * generic operations to perform read, write and monitor operations. The asset * only specifies the channel specific configuration (which is very channel * descriptor specific) and the associated driver is mainly responsible for * performing all the lower level tasks on the provided channel configuration. * * @see AssetRecord * @see AssetConfiguration * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface Asset { /** * Gets the asset configuration. * * @return the asset configuration */ public AssetConfiguration getAssetConfiguration(); /** * Reads the communication channels identified by the set of channel names provided as argument. * The read result is returned as a list of channel records. * If for some reason the value of a channel cannot be read, * a channel record containing a proper channel flag should be returned anyways. * The channel flag shall best describe the reason of failure. * If the connection to the asset is interrupted, then any necessary resources * that correspond to this connection should be cleaned up and a {@code KuraException} shall be * thrown. * * @param channelNames * the set of channel names which are to be read. The channel name * must be unique for every channel belonging to an asset. * Channel names are case sensitive. * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the asset then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} * @throws KuraException * if the connection to the asset was interrupted, then error * code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set * in the thrown {@link KuraException}. * @throws NullPointerException * if argument is null * @return the list of channel records which comprises the currently read * value in case of success or the reason of failure */ public List read(Set channelNames) throws KuraException; /** * Performs a read on all READ or READ_WRITE channels that are defined on this asset and returns * the result as a list of {@link ChannelRecord} instances. * * @see Asset#read(List) * * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the asset then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} * @throws KuraException * if the connection to the asset was interrupted, then error * code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set * in the thrown {@link KuraException}. * @return the list of channel records which comprises the currently read * value in case of success or the reason of failure */ public List readAllChannels() throws KuraException; /** * Registers a channel listener for the provided channel name for a monitor * operation on it. * * @param channelName * the channel name. The channel name * must be unique for every channel belonging to an asset. * Channel names are case sensitive. * @param channelListener * the channel listener * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the asset then specific * error code {@link org.eclipse.kura.KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} * @throws KuraException * if the connection to the asset was interrupted, then error * code {@link org.eclipse.kura.KuraErrorCode#CONNECTION_FAILED} needs to be set * in the thrown {@link KuraException} and if the channel is not * present, error code {@link org.eclipse.kura.KuraErrorCode#INTERNAL_ERROR} * needs to be set in the thrown {@link KuraException}. For any * other internal exception, then error code * {@link org.eclipse.kura.KuraErrorCode#INTERNAL_ERROR} will be set. * @throws NullPointerException * if any of the arguments is null * @throws IllegalArgumentException * If the provided channel name is not present in the configuration * of this asset */ public void registerChannelListener(String channelName, ChannelListener channelListener) throws KuraException; /** * Unregisters a already registered channel listener which has been registered * for a monitor operation * * @param channelListener * the channel listener to unregister * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the asset then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} * @throws KuraException * For any other internal exception, then error code * {@code KuraErrorCode#INTERNAL_ERROR} will be set. * @throws NullPointerException * if argument is null */ public void unregisterChannelListener(ChannelListener channelListener) throws KuraException; /** * Writes the data to the provided communication channels that correspond to * the given channel records. The write result is returned by setting the * channel flag {@link org.eclipse.kura.channel.ChannelFlag#SUCCESS} in the provided channel * records. If the connection to the asset is interrupted, then any * necessary resources that correspond to this connection should be cleaned * up and a {@link KuraException} with a suitable error code shall be * thrown. * * @param channelRecords * the channel records hold the information of what channels are to * be written and the values that are to be written. They will be * filled by this function with a channel flag stating whether the * write process is successful or not. * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the asset then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} * @throws KuraException * if the connection to the asset was interrupted, then error * code {@code KuraErrorCode#CONNECTION_FAILED} needs to be set * in the thrown {@link KuraException} * @throws NullPointerException * if argument is null */ public void write(List channelRecords) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/AssetConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.asset; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.eclipse.kura.channel.Channel; import org.osgi.annotation.versioning.ProviderType; /** * The Class AssetConfiguration is responsible for storing the configuration for * an industrial device (also known as Asset in the context of Eclipse * Kura).
*
* * @see Channel * @see org.eclipse.kura.channel.ChannelType * @see org.eclipse.kura.type.DataType * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class AssetConfiguration { /** * The list of channels associated with this asset. The association denotes * channel name and its actual object reference pair. */ private final Map assetChannels; /** the asset description. */ private String assetDescription; /** the driver PID as associated with this asset. */ private final String driverPid; /** * Instantiates a new asset configuration. * * @param description * the description of the asset * @param driverPid * the driver PID * @param channels * the map of all channel configurations * @throws NullPointerException * if any of the arguments is null */ public AssetConfiguration(final String description, final String driverPid, final Map channels) { requireNonNull(description, "Asset description cannot be null"); requireNonNull(driverPid, "Asset driver PID cannot be null"); requireNonNull(channels, "Asset channel configurations cannot be null"); this.assetDescription = description; this.driverPid = driverPid; this.assetChannels = Collections.unmodifiableMap(channels); } /** * Gets the asset channels. * * @return the asset channels */ public Map getAssetChannels() { return this.assetChannels; } /** * Gets the asset description. * * @return the asset description */ public String getAssetDescription() { return this.assetDescription; } /** * Gets the driver PID. * * @return the driver PID */ public String getDriverPid() { return this.driverPid; } /** * Sets the asset description. * * @param description * the new asset description * @throws NullPointerException * if the argument is null */ public void setAssetDescription(final String description) { requireNonNull(description, "Asset description cannot be null"); this.assetDescription = description; } /** {@inheritDoc} */ @Override public String toString() { return "AssetConfiguration [channels=" + this.assetChannels + ", description=" + this.assetDescription + ", driverPid=" + this.driverPid + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/AssetService.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.asset; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * The interface AssetService is an utility service API to provide useful * methods for assets * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface AssetService { /** * Gets the asset instance by the provided asset PID * ({@code kura.service.pid}). * * @param assetPid * the asset PID to check * @return the asset instance * @throws NullPointerException * if the provided asset PID is null */ public Asset getAsset(String assetPid); /** * Gets the asset PID. ({@code kura.service.pid}) by the provided asset * instance * * @param asset * the asset instance to check * @return the asset PID * @throws NullPointerException * if the provided asset instance is null */ public String getAssetPid(Asset asset); /** * Returns the list containing all the available asset instances * * @return the list of assets available in service registry or empty list * if no assets are available */ public List listAssets(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/asset/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides all necessary APIs for Kura Asset Component Model * * @since 1.2 */ package org.eclipse.kura.asset; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/AuditConstants.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.audit; import org.osgi.annotation.versioning.ProviderType; /** * Provides some well known audit context properties. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public enum AuditConstants { /** * Contains an identifier for the entry point associated with an audit context. It must always be present. */ KEY_ENTRY_POINT("entrypoint"), /** * Reports the IP address of the device that performed a request. It can be missing. */ KEY_IP("ip"), /** * Reports the IP address of the Kura Identity associated with a request. It can be missing. */ KEY_IDENTITY("identity"), /** * A value for the entrypoint that indicates a context created by an internal framework * component and not associated with an external entity. */ ENTRY_POINT_INTERNAL("Internal"); private final String value; AuditConstants(final String value) { this.value = value; } public String getValue() { return value; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/AuditContext.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.audit; import static java.util.Objects.requireNonNull; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Represents a context that can be created by a framework entry point for audit purposes. Examples of entry points * are the Web UI, a cloud connection or the Rest service. * An AuditContext contains a set of properties. Some property are well known and described by the * {@link AuditConstants} enumeration, other custom properties can be added by the entry point implementation. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public class AuditContext { private static ThreadLocal localContext = new ThreadLocal<>(); private final Map properties; /** * Creates a new {@link AuditContext}. * * @param properties * The properties to be associated with this context. It must be a non null mutable map. */ public AuditContext(final Map properties) { this.properties = requireNonNull(properties); } /** * Returns the properties associated with this context * * @return the properties. */ public Map getProperties() { return this.properties; } /** * {@inheritDoc} */ @Override public String toString() { return properties.toString().replaceAll("[\n\r\t]", "_"); } /** * Creates a copy of this AuditContext with a new and independent set of properties. * * @return a copy of this AuditContext. */ public AuditContext copy() { return new AuditContext(new HashMap<>(this.properties)); } /** * Returns the {@link AuditContext} associated with the current thread, if set, or a context with * {@link AuditConstants#KEY_ENTRY_POINT} set to {@link AuditConstants#ENTRY_POINT_INTERNAL} otherwise. * * @return the {@link AuditContext} */ public static AuditContext currentOrInternal() { final AuditContext current = localContext.get(); if (current != null) { return current; } else { final Map properties = new HashMap<>(1); properties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), "Internal"); return new AuditContext(properties); } } /** * Returns the {@link AuditContext} associated with the current thread, if any. * * @return the {@link AuditContext} associated with this thread or empty if none is set */ public static Optional current() { return Optional.ofNullable(localContext.get()); } /** * Sets the provided context as the thread local instance and returns a {@link Scope} that can be used for removing * it. * Subsequent calls to {@link AuditContext#currentOrInternal()} performed on the same thread will return the * provided * {@link AuditContext} instance until the returned {@link Scope} is closed. * * @param context * the context * @return a {@link Scope} that removes the thread local context when closed. */ public static Scope openScope(final AuditContext context) { return new Scope(context); } /** * Resents an {@link AutoCloseable} scope that removes the associated {@link AuditContext} when closed. * See {@link AuditContext#openScope(AuditContext)} for more details. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public static class Scope implements AutoCloseable { private final AuditContext context; private Scope(final AuditContext context) { this.context = context; localContext.set(context); } /** * Removes the associated {@link AuditContext} from thread local storage. * * {@inheritDoc} */ @Override public void close() { if (localContext.get() == context) { localContext.remove(); } } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/audit/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides functionalities to track entry point information for audit purposes. * */ package org.eclipse.kura.audit; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeAdapter.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.List; import java.util.UUID; import java.util.concurrent.Future; import java.util.function.Consumer; import org.eclipse.kura.KuraBluetoothDiscoveryException; import org.eclipse.kura.KuraBluetoothRemoveException; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothAdapter represents the physical Bluetooth adapter on the host machine (ex: hci0). * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeAdapter { /** * Search for a BLE device with the specified address. The method will perform a BLE discovery for at most timeout * seconds or until the device is found. It will return a Future instance and the discovered device can be * retrieved using the get() method. The get(long timeout, TimeUnit unit) is not supported and acts as the get() * method. * * @param timeout * timeout in seconds for device discovery * @param address * MAC address of the BLE device * @return Future */ public Future findDeviceByAddress(long timeout, String address); /** * Search for a BLE device with the specified name. The method will perform a BLE discovery for at most timeout * seconds or until the device is found. It will return a Future instance and the discovered device can be * retrieved using the get() method. The get(long timeout, TimeUnit unit) is not supported and acts as the get() * method. * * @param timeout * timeout in seconds for device discovery * @param name * system name of the BLE device * @return Future */ public Future findDeviceByName(long timeout, String name); /** * Search for a BLE device with the specified address. The method will perform a BLE discovery for at most timeout * seconds or until the device is found. When the device is found or the timeout is reached the consumer is used to * get the device. * * @param timeout * timeout in seconds for device discovery * @param address * MAC address of the BLE device * @param consumer * the consumer used to get the device */ public void findDeviceByAddress(long timeout, String address, Consumer consumer); /** * Search for a BLE device with the specified name. The method will perform a BLE discovery for at most timeout * seconds or until the device is found. When the device is found or the timeout is reached the consumer is used to * get the device. * * @param timeout * timeout in seconds for device discovery * @param name * system name of the BLE device * @param consumer * the consumer used to get the device */ public void findDeviceByName(long timeout, String name, Consumer consumer); /** * Search for BLE devices. The method will perform a BLE discovery for timeout seconds. It will return a Future * instance and the discovered devices can be retrieved using the get() method. The get(long timeout, TimeUnit unit) * is not supported and acts as the get() method. * * @param timeout * timeout in seconds for device discovery * @return Future */ public Future> findDevices(long timeout); /** * Search for BLE devices. The method will perform a BLE discovery for timeout seconds. When the timeout is reached * the consumer is used to get the devices. * * @param timeout * timeout in seconds for device discovery * @param consumer * the consumer used to get the device */ public void findDevices(long timeout, Consumer> consumer); /** * Starts a BLE discovery. * * @throws KuraBluetoothDiscoveryException * @since 2.2 */ public void startDiscovery() throws KuraBluetoothDiscoveryException; /** * Stops a BLE discovery. * * @throws KuraBluetoothDiscoveryException */ public void stopDiscovery() throws KuraBluetoothDiscoveryException; /** * Returns the hardware address of this adapter. * * @return The hardware address of this adapter. */ public String getAddress(); /** * Returns the system name of this adapter. * * @return The system name of this adapter. */ public String getName(); /** * Returns the interface name of this adapter. * * @return The interface name of this adapter. */ public String getInterfaceName(); /** * Returns the local ID of the adapter. * * @return The local ID of the adapter. */ public String getModalias(); /** * Returns the friendly name of this adapter. * * @return The friendly name of this adapter, or NULL if not set. */ public String getAlias(); /** * Sets the friendly name of this adapter. * */ public void setAlias(String value); /** * Returns the Bluetooth class of the adapter. * * @return The Bluetooth class of the adapter. */ public long getBluetoothClass(); /** * Returns the power state the adapter. * * @return The power state of the adapter. */ public boolean isPowered(); /** * Sets the power state the adapter. */ public void setPowered(boolean value); /** * Returns the discoverable state the adapter. * * @return The discoverable state of the adapter. */ public boolean isDiscoverable(); /** * Sets the discoverable state the adapter. */ public void setDiscoverable(boolean value); /** * Returns the discoverable timeout the adapter. * * @return The discoverable timeout of the adapter. */ public long getDiscoverableTimeout(); /** * Sets the discoverable timeout the adapter. A value of 0 disables * the timeout. * * @deprecated since 2.2 use instead {@link setDiscoverableTimeout} */ @Deprecated public void setDiscoverableTimout(long value); /** * Sets the discoverable timeout the adapter. A value of 0 disables * the timeout. * * @since 2.2 */ public void setDiscoverableTimeout(long value); /** * Returns the pairable state the adapter. * * @return The pairable state of the adapter. */ public boolean isPairable(); /** * Sets the discoverable state the adapter. */ public void setPairable(boolean value); /** * Returns the timeout in seconds after which pairable state turns off * automatically, 0 means never. * * @return The pairable timeout of the adapter. */ public long getPairableTimeout(); /** * Sets the timeout after which pairable state turns off automatically, 0 means never. */ public void setPairableTimeout(long value); /** * Returns the discovering state the adapter. * * @return The discovering state of the adapter. */ public boolean isDiscovering(); /** * Returns the UUIDs of the adapter. * * @return Array containing the UUIDs of the adapter. */ public UUID[] getUUIDs(); /** * Remove all the known devices from the system. Be aware that after the removing the objects representing the * devices will not be valid anymore and any operation on them will have no effect. * * @return The number of devices removed from internal list * @throws KuraBluetoothRemoveException * * @since 2.0 */ public int removeDevices() throws KuraBluetoothRemoveException; /** * Sets a scan filter for this adapter. * *

* When a remote device is found that advertises any UUID from UUIDs, it will be reported if: *

    *
  • Pathloss and RSSI are both empty.
  • *
  • only Pathloss param is set, device advertise TX power, and computed pathloss is less than Pathloss * param.
  • *
  • only RSSI param is set, and received RSSI is higher than RSSI param.
  • *
*

* *

* If "auto" transport is requested, scan will use LE, BREDR, or both, depending on what's * currently enabled on the controller. * * To remove the filter, call this method with empty parameters. * * @param uuids * the uuids advertised by the devices * @param rssi * the Receiver Signal Strength Indication value * @param pathloss * the pathloss value * @param trasportType * the trasportType (LE or BREDR) * * @deprecated use instead {@link setDiscoveryFilter(List, int, int, BluetoothTransportType, boolean)} * @since 2.0 */ @Deprecated public void setDiscoveryFilter(List uuids, int rssi, int pathloss, BluetoothTransportType transportType); /** * Sets a scan filter for this adapter. * *

* When a remote device is found that advertises any UUID from UUIDs, it will be reported if: *

    *
  • Pathloss and RSSI are both empty.
  • *
  • only Pathloss param is set, device advertise TX power, and computed pathloss is less than Pathloss * param.
  • *
  • only RSSI param is set, and received RSSI is higher than RSSI param.
  • *
*

* *

* If "auto" transport is requested, scan will use LE, BREDR, or both, depending on what's * currently enabled on the controller. * * To remove the filter, call this method with empty parameters. * * @param uuids * the uuids advertised by the devices * @param rssi * the Receiver Signal Strength Indication value * @param pathloss * the pathloss value * @param trasportType * the trasportType (LE or BREDR) * @param duplicateData * whether to filter duplicate data * * @since 2.2 */ public void setDiscoveryFilter(List uuids, int rssi, int pathloss, BluetoothTransportType transportType, boolean duplicateData); /** * Set a device discovery filter based on RSSI value. Only devices with rssi greater than the provided value will be * reported. Set it to 0 to remove the filter. * * @param rssi * the Receiver Signal Strength Indication value used by the filter * * @since 2.0 */ public void setRssiDiscoveryFilter(int rssi); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeDevice.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.List; import java.util.Map; import java.util.UUID; import org.eclipse.kura.KuraBluetoothConnectionException; import org.eclipse.kura.KuraBluetoothPairException; import org.eclipse.kura.KuraBluetoothRemoveException; import org.eclipse.kura.KuraBluetoothResourceNotFoundException; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeDevice represents a Bluetooth LE device to which connections * may be made. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeDevice { /** * Find a BluetoothLeGattService specifying the UUID of the service. * * @param uuid * The UUID of the GATT service * @return The BluetoothLeGattService * @throws KuraBluetoothResourceNotFoundException */ public BluetoothLeGattService findService(UUID uuid) throws KuraBluetoothResourceNotFoundException; /** * Find a BluetoothLeGattService specifying the UUID of the service and the timeout in seconds. * * @since 1.4 * @param uuid * The UUID of the GATT service * @param timeout * The timeout for retrieving the service * @return The BluetoothLeGattService * @throws KuraBluetoothResourceNotFoundException * * @deprecated since 2.2 use instead {@link findService(UUID)} */ @Deprecated public BluetoothLeGattService findService(UUID uuid, long timeout) throws KuraBluetoothResourceNotFoundException; /** * Returns a list of BluetoothGattServices available on this device. * * @return A list of BluetoothLeGattService * @throws KuraBluetoothResourceNotFoundException */ public List findServices() throws KuraBluetoothResourceNotFoundException; /** * Disconnect from this device, removing all connected profiles. * * @throws KuraBluetoothConnectionException */ public void disconnect() throws KuraBluetoothConnectionException; /** * A connection to this device is established, connecting each profile * flagged as auto-connectable. * * @throws KuraBluetoothConnectionException */ public void connect() throws KuraBluetoothConnectionException; /** * Connects a specific profile available on the device, given by UUID * * @param uuid * The UUID of the profile to be connected * @throws KuraBluetoothConnectionException */ public void connectProfile(UUID uuid) throws KuraBluetoothConnectionException; /** * Disconnects a specific profile available on the device, given by UUID * * @param uuid * The UUID of the profile to be disconnected * @throws KuraBluetoothConnectionException */ public void disconnectProfile(UUID uuid) throws KuraBluetoothConnectionException; /** * A connection to this device is established, and the device is then * paired. * * @throws KuraBluetoothPairException */ public void pair() throws KuraBluetoothPairException; /** * Cancel a pairing operation * * @throws KuraBluetoothPairException */ public void cancelPairing() throws KuraBluetoothPairException; /** * Returns the hardware address of this device. * * @return The hardware address of this device. */ public String getAddress(); /** * Returns the remote friendly name of this device. * * @return The remote friendly name of this device, or NULL if not set. */ public String getName(); /** * Returns an alternative friendly name of this device. * * @return The alternative friendly name of this device, or NULL if not set. */ public String getAlias(); /** * Sets an alternative friendly name of this device. */ public void setAlias(String value); /** * Returns the Bluetooth class of the device. * * @return The Bluetooth class of the device. */ public int getBluetoothClass(); /** * Returns the appearance of the device, as found by GAP service. * * @return The appearance of the device, as found by GAP service. */ public short getAppearance(); /** * Returns the proposed icon name of the device. * * @return The proposed icon name, or NULL if not set. */ public String getIcon(); /** * Returns the paired state the device. * * @return The paired state of the device. */ public boolean isPaired(); /** * Returns the trusted state the device. * * @return The trusted state of the device. */ public boolean isTrusted(); /** * Sets the trusted state the device. */ public void setTrusted(boolean value); /** * Returns the blocked state the device. * * @return The blocked state of the device. */ public boolean isBlocked(); /** * Sets the blocked state the device. */ public void setBlocked(boolean value); /** * Returns if device uses only pre-Bluetooth 2.1 pairing mechanism. * * @return True if device uses only pre-Bluetooth 2.1 pairing mechanism. */ public boolean isLegacyPairing(); /** * Returns the Received Signal Strength Indicator of the device. * * @return The Received Signal Strength Indicator of the device. */ public short getRSSI(); /** * Returns the connected state of the device. * * @return The connected state of the device. */ public boolean isConnected(); /** * Returns the UUIDs of the device. * * @return Array containing the UUIDs of the device, ends with NULL. */ public UUID[] getUUIDs(); /** * Returns the local ID of the adapter. * * @return The local ID of the adapter. */ public String getModalias(); /** * Returns the adapter on which this device was discovered or * connected. * * @return The adapter. */ public BluetoothLeAdapter getAdapter(); /** * Returns a map containing manufacturer specific advertisement data. * An entry has a short key and an array of bytes. * * @return manufacturer specific advertisement data. */ public Map getManufacturerData(); /** * Returns a map containing service advertisement data. * An entry has a UUID key and an array of bytes. * * @return service advertisement data. */ public Map getServiceData(); /** * Returns the transmission power level (0 means unknown). * * @return the transmission power level (0 means unknown). */ public short getTxPower(); /** * Returns if the service discovery is ended. * * @since 2.0 */ public boolean isServicesResolved(); /** * Remove this device from the system. Be aware that after the removing the object representing the device * will not be valid anymore and any operation on it will have no effect. * * @return TRUE if the device has been removed * @throws BluetKuraBluetoothRemoveExceptionoothException * * @since 2.0 * @deprecated since 2.2 use instead {@link removeDevice} */ @Deprecated public boolean remove() throws KuraBluetoothRemoveException; /** * Remove this device from the system. Be aware that after the removing the object representing the device * will not be valid anymore and any operation on it will have no effect. * * @throws BluetKuraBluetoothRemoveExceptionoothException * * @since 2.2 */ public void removeDevice() throws KuraBluetoothRemoveException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattCharacteristic.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.List; import java.util.UUID; import java.util.function.Consumer; import org.eclipse.kura.KuraBluetoothIOException; import org.eclipse.kura.KuraBluetoothNotificationException; import org.eclipse.kura.KuraBluetoothResourceNotFoundException; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeGattCharacteristic represents a GATT characteristic. * If an application uses value notifications, it has to keep a reference to the corresponding GATT characteristic to * avoid that the garbage collector deletes it and removes the associated consumer. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeGattCharacteristic { /** * Find a BluetoothLeGattDescriptor specifying the UUID of the descriptor. * * @param uuid * The UUID of the GATT descriptor * @return The BluetoothLeGattDescriptor * @throws KuraBluetoothResourceNotFoundException */ public BluetoothLeGattDescriptor findDescriptor(UUID uuid) throws KuraBluetoothResourceNotFoundException; /** * Find a BluetoothLeGattDescriptor specifying the UUID of the descriptor and the timeout in seconds. * * @since 1.4 * @param uuid * The UUID of the GATT descriptor * @param timeout * The timeout for retrieving the characteristic * @return The BluetoothLeGattDescriptor * @throws KuraBluetoothResourceNotFoundException * * @deprecated since 2.2 use instead {@link findDescriptor(UUID)} */ @Deprecated public BluetoothLeGattDescriptor findDescriptor(UUID uuid, long timeout) throws KuraBluetoothResourceNotFoundException; /** * Returns a list of BluetoothLeGattDescriptors available on this characteristic. * * @return A list of BluetoothLeGattDescriptor * @throws KuraBluetoothResourceNotFoundException */ public List findDescriptors() throws KuraBluetoothResourceNotFoundException; /** * Reads the value of this characteristic. * * @return A byte[] containing the value of this characteristic. * @throws KuraBluetoothIOException */ public byte[] readValue() throws KuraBluetoothIOException; /** * Enables notifications for the value and calls accept function of the Consumer * object. It enables notifications for this characteristic at BLE level. * If an application uses value notifications, it has to keep a reference to the corresponding GATT characteristic * to avoid that the garbage collector deletes it and removes the associated consumer. * * @param callback * A Consumer object. Its accept function will be called * when a notification is issued. * * @throws KuraBluetoothNotificationException */ public void enableValueNotifications(Consumer callback) throws KuraBluetoothNotificationException; /** * Disables notifications of the value and unregisters the consumer object * passed through the corresponding enable method. It disables notifications * at BLE level for this characteristic. * * @throws KuraBluetoothNotificationException */ public void disableValueNotifications() throws KuraBluetoothNotificationException; /** * Writes the value of this characteristic. * * @param value * The data as byte[] to be written * * @throws KuraBluetoothIOException */ public void writeValue(byte[] value) throws KuraBluetoothIOException; /** * Get the UUID of this characteristic. * * @return The 128 byte UUID of this characteristic, NULL if an error occurred */ public UUID getUUID(); /** * Returns the service to which this characteristic belongs to. * * @return The BluetoothLeGattService. */ public BluetoothLeGattService getService(); /** * Returns the cached value of this characteristic, if any. * * @return The cached value of this characteristic. */ public byte[] getValue(); /** * Returns true if notification for changes of this characteristic are * activated. * * @return True if notificatios are activated. */ public boolean isNotifying(); /** * Returns the list of BluetoothLeGattCharacteristicProperties this characteristic has. * * @return A list of BluetoothLeGattCharacteristicProperties for this characteristic. */ public List getProperties(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattCharacteristicProperties.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeGattCharacteristicProperties contains the GATT characteristic property values * * @since 1.3 */ @ProviderType public enum BluetoothLeGattCharacteristicProperties { BROADCAST(0x01), READ(0x02), WRITE_WITHOUT_RESPONSE(0x04), WRITE(0x08), NOTIFY(0x10), INDICATE(0x20), AUTHENTICATE_SIGNED_WRITES(0x40), EXTENDED_PROPERTIES(0x80), UNKNOWN(0x00); private final int code; private BluetoothLeGattCharacteristicProperties(int code) { this.code = code; } public int getCode() { return this.code; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.UUID; import org.eclipse.kura.KuraBluetoothIOException; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeGattDescriptor represents a GATT descriptor. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeGattDescriptor { /** * Reads the value of this descriptor * * @return A byte[] containing data from this descriptor * @throws KuraBluetoothIOException */ public byte[] readValue() throws KuraBluetoothIOException; /** * Writes the value of this descriptor. * * @param value * The data as byte[] to be written * @throws KuraBluetoothIOException */ public void writeValue(byte[] value) throws KuraBluetoothIOException; /** * Get the UUID of this descriptor. * * @return The 128 byte UUID of this descriptor, NULL if an error occurred */ public UUID getUUID(); /** * Returns the characteristic to which this descriptor belongs to. * * @return The characteristic. */ public BluetoothLeGattCharacteristic getCharacteristic(); /** * Returns the cached value of this descriptor, if any. * * @return The cached value of this descriptor. */ public byte[] getValue(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeGattService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.List; import java.util.UUID; import org.eclipse.kura.KuraBluetoothResourceNotFoundException; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeGattService represents a GATT service. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeGattService { /** * Find a BluetoothLeGattCharacteristic specifying the UUID of the characteristic. * * @param uuid * The UUID of the GATT characteristic * @return The BluetoothLeGattCharacteristic * @throws KuraBluetoothResourceNotFoundException */ public BluetoothLeGattCharacteristic findCharacteristic(UUID uuid) throws KuraBluetoothResourceNotFoundException; /** * Find a BluetoothLeGattCharacteristic specifying the UUID of the characteristic and the timeout in seconds. * * @since 1.4 * @param uuid * The UUID of the GATT characteristic * @param timeout * The timeout for retrieving the service * @return The BluetoothLeGattCharacteristic * @throws KuraBluetoothResourceNotFoundException * * @deprecated since 2.2 use instead {@link findCharacteristic(UUID)} */ @Deprecated public BluetoothLeGattCharacteristic findCharacteristic(UUID uuid, long timeout) throws KuraBluetoothResourceNotFoundException; /** * Returns a list of BluetoothLeGattCharacteristic available on this service. * * @return A list of BluetoothLeGattCharacteristic * @throws KuraBluetoothResourceNotFoundException */ public List findCharacteristics() throws KuraBluetoothResourceNotFoundException; /** * Get the UUID of this service * * @return The 128 byte UUID of this service, NULL if an error occurred */ public UUID getUUID(); /** * Returns the device to which this service belongs to. * * @return The device. */ public BluetoothLeDevice getDevice(); /** * Returns true if this service is a primary service, false if secondary. * * @return true if this service is a primary service, false if secondary. */ public boolean isPrimary(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothLeService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeService provides a mechanism for interfacing with Bluetooth LE devices. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeService { /** * Return a list of available Bluetooth adapters. */ public List getAdapters(); /** * Search for a Bluetooth adapter with the specified interface name (i.e. hci0). * If the adapter is not available, it returns null. * * @param interfaceName * the name of the adapter (i.e. hci0) */ public BluetoothLeAdapter getAdapter(String interfaceName); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/BluetoothTransportType.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.bluetooth.le; import org.osgi.annotation.versioning.ProviderType; /** * Defines the type of transport for Bluetooth devices. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public enum BluetoothTransportType { AUTO, BREDR, LE } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportAddressType.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; /** * AdvertisingReportAddressType represents the type of address in to the advertising packet. * Possible values are: * 0x00 : Public Device Address * 0x01 : Random Device Address * 0x02 : Public Identity Address * 0x03 : Random Identity Address * 0xFE : Unresolved * * @since 1.3 */ public enum AdvertisingReportAddressType { PUBLIC((byte) 0x00), RANDOM((byte) 0x01), /** * @since 2.2 */ PUBLIC_IDENTITY((byte) 0x02), /** * @since 2.2 */ RANDOM_IDENTITY((byte) 0x03), /** * @since 2.2 */ UNRESOLVED((byte) 0xFE); private final byte addressType; private AdvertisingReportAddressType(byte addressType) { this.addressType = addressType; } public byte getEventTypeCode() { return this.addressType; } public static AdvertisingReportAddressType valueOf(byte address) { AdvertisingReportAddressType type; if (address == PUBLIC.getEventTypeCode()) { type = PUBLIC; } else if (address == RANDOM.getEventTypeCode()) { type = RANDOM; } else if (address == PUBLIC_IDENTITY.getEventTypeCode()) { type = PUBLIC_IDENTITY; } else if (address == RANDOM_IDENTITY.getEventTypeCode()) { type = RANDOM_IDENTITY; } else if (address == UNRESOLVED.getEventTypeCode()) { type = UNRESOLVED; } else { throw new IllegalArgumentException("Address type not recognized"); } return type; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportEventType.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Scott Ware ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.osgi.annotation.versioning.ProviderType; /** * AdvertisingReportEventType represents the event type of an advertising packet. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public enum AdvertisingReportEventType { ADV_IND((byte) 0x00), ADV_DIRECT_IND((byte) 0x01), ADV_SCAN_IND((byte) 0x02), ADV_NONCONN_IND((byte) 0x03), SCAN_RSP((byte) 0x04), /** * @since 2.2 */ ADV_IND_EXT((byte) 0x13), /** * @since 2.2 */ ADV_DIRECT_IND_EXT((byte) 0x15), /** * @since 2.2 */ ADV_SCAN_IND_EXT((byte) 0x12), /** * @since 2.2 */ ADV_NONCONN_IND_EXT((byte) 0x10), /** * @since 2.2 */ SCAN_RSP_ADV_IND_EXT((byte) 0x1B), /** * @since 2.2 */ SCAN_RSP_ADV_SCAN_IND_EXT((byte) 0x1A), /** * @since 2.2 */ DATA_STATUS_COMPLETED((byte) 0x00), /** * @since 2.2 */ DATA_STATUS_INCOMPLETE_ONGOING((byte) 0x20), /** * @since 2.2 */ DATA_STATUS_INCOMPLETE_FINISHED((byte) 0x40); private DataStatus dataStatus = DataStatus.UNKNOWN; private boolean connectable = false; private boolean directed = false; private boolean scannable = false; private boolean scanResponse = false; private final byte eventType; private AdvertisingReportEventType(byte eventType) { this.eventType = eventType; } /** * @since 2.2 */ public DataStatus getDataStatus() { return this.dataStatus; } /** * @since 2.2 */ public boolean isConnectable() { return connectable; } /** * @since 2.2 */ public boolean isDirected() { return directed; } /** * @since 2.2 */ public boolean isScannable() { return scannable; } /** * @since 2.2 */ public boolean isScanResponse() { return scanResponse; } /** * @since 2.2 */ public byte getEventTypeCode() { return this.eventType; } /** * @since 2.2 */ public static AdvertisingReportEventType valueOf(int event, boolean extendedReport) { AdvertisingReportEventType type = null; // Extended report has scope to use 2 octets but currently only uses 1 byte eventData = (byte) (event & 0xFF); if (extendedReport) { type = getLegacyType(event, eventData); } else { if (event == ADV_IND.eventType) { type = ADV_IND; type.connectable = true; } else if (event == ADV_DIRECT_IND.eventType) { type = ADV_DIRECT_IND; type.connectable = true; type.directed = true; } else if (event == ADV_SCAN_IND.eventType) { type = ADV_SCAN_IND; type.scannable = true; } else if (event == SCAN_RSP.eventType) { type = SCAN_RSP; type.scanResponse = true; } else if (event == ADV_NONCONN_IND.eventType) { type = ADV_NONCONN_IND; } else { throw new IllegalArgumentException("Report Event type not recognized"); } } return type; } private static AdvertisingReportEventType getLegacyType(int event, byte eventData) { AdvertisingReportEventType type = null; // Check for legacy advertising PDU if ((eventData & 0x10) == 0) { // Data Status byte status = (byte) (eventData & 0x60); if (status == DATA_STATUS_COMPLETED.eventType) { type = DATA_STATUS_COMPLETED; type.dataStatus = DataStatus.COMPLETED; } else if (status == DATA_STATUS_INCOMPLETE_ONGOING.eventType) { type = DATA_STATUS_INCOMPLETE_ONGOING; type.dataStatus = DataStatus.INCOMPLETE_ONGOING; } else if (status == DATA_STATUS_INCOMPLETE_FINISHED.eventType) { type = DATA_STATUS_INCOMPLETE_FINISHED; type.dataStatus = DataStatus.INCOMPLETE_FINISHED; } else { throw new IllegalArgumentException("Data status type not recognized"); } // Connectable Flag type.connectable = (eventData & 0x01) != 0; // Scannable Flag type.scannable = (eventData & 0x02) != 0; // Directed Flag type.directed = (eventData & 0x04) != 0; // Scan Response Flag type.scanResponse = (eventData & 0x08) != 0; } else { if (event == ADV_IND_EXT.eventType) { type = ADV_IND_EXT; type.connectable = true; } else if (event == ADV_DIRECT_IND_EXT.eventType) { type = ADV_DIRECT_IND_EXT; type.connectable = true; type.directed = true; } else if (event == ADV_SCAN_IND_EXT.eventType) { type = ADV_SCAN_IND_EXT; type.scannable = true; } else if (event == SCAN_RSP_ADV_IND_EXT.eventType) { type = SCAN_RSP_ADV_IND_EXT; type.connectable = true; type.scanResponse = true; } else if (event == SCAN_RSP_ADV_SCAN_IND_EXT.eventType) { type = SCAN_RSP_ADV_SCAN_IND_EXT; type.scannable = true; type.scanResponse = true; } else if (event == ADV_NONCONN_IND_EXT.eventType) { type = ADV_NONCONN_IND_EXT; } else { throw new IllegalArgumentException("Report Event type not recognized"); } } return type; } /** * * @deprecated since 2.2 use instead {@link valueOf(int event, boolean extendedReport)} */ @Deprecated public static AdvertisingReportEventType valueOf(byte event) { return valueOf(event, false); } /** * @since 2.2 */ public enum DataStatus { UNKNOWN, COMPLETED, INCOMPLETE_ONGOING, INCOMPLETE_FINISHED } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportPhy.java ================================================ /******************************************************************************* * Copyright (c) 2020, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Scott Ware * Eurotech *******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; /** * AdvertisingReportPhy represents the Bluetooth physical layer (PHY) variant used for an advertising report. * Possible values are: * 0x00 : None * 0x01 : LE 1M * 0x02 : LE 2M * 0x03 : LE Coded * * @since 2.2 */ public enum AdvertisingReportPhy { NONE((byte) 0x00), LE_1M((byte) 0x01), LE_2M((byte) 0x02), LE_CODED((byte) 0x03); private final byte phy; private AdvertisingReportPhy(byte phy) { this.phy = phy; } public byte getPhyCode() { return this.phy; } public static AdvertisingReportPhy valueOf(byte phy) { AdvertisingReportPhy value; if (phy == NONE.getPhyCode()) { value = NONE; } else if (phy == LE_1M.getPhyCode()) { value = LE_1M; } else if (phy == LE_2M.getPhyCode()) { value = LE_2M; } else if (phy == LE_CODED.getPhyCode()) { value = LE_CODED; } else { throw new IllegalArgumentException("PHY variant not recognized"); } return value; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/AdvertisingReportRecord.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Scott Ware ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.osgi.annotation.versioning.ProviderType; /** * AdvertisingReportRecord contains all the fields of a advertising record. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public class AdvertisingReportRecord { private AdvertisingReportEventType eventType; private AdvertisingReportAddressType addressType; private String address; private AdvertisingReportAddressType directAddressType; private String directAddress; private AdvertisingReportPhy primaryPhy; private AdvertisingReportPhy secondaryPhy; private byte[] reportData; private int sid; private int txPower; private int periodicAdvertisingInterval; private int length; private int rssi; private boolean extended; public AdvertisingReportEventType getEventType() { return this.eventType; } public void setEventType(int eventType) { this.eventType = AdvertisingReportEventType.valueOf((byte) eventType, this.extended); } public AdvertisingReportAddressType getAddressType() { return this.addressType; } public void setAddressType(int addressType) { this.addressType = AdvertisingReportAddressType.valueOf((byte) addressType); } public String getAddress() { return this.address; } public void setAddress(String address) { this.address = address; } /** * @since 2.2 */ public AdvertisingReportAddressType getDirectAddressType() { return this.directAddressType; } /** * @since 2.2 */ public void setDirectAddressType(int addressType) { this.directAddressType = AdvertisingReportAddressType.valueOf((byte) addressType); } /** * @since 2.2 */ public String getDirectAddress() { return this.directAddress; } /** * @since 2.2 */ public void setDirectAddress(String address) { this.directAddress = address; } /** * @since 2.2 */ public AdvertisingReportPhy getPrimaryPhy() { return this.primaryPhy; } /** * @since 2.2 */ public void setPrimaryPhy(int phy) { this.primaryPhy = AdvertisingReportPhy.valueOf((byte) phy); } /** * @since 2.2 */ public AdvertisingReportPhy getSecondaryPhy() { return this.secondaryPhy; } /** * @since 2.2 */ public void setSecondaryPhy(int phy) { this.secondaryPhy = AdvertisingReportPhy.valueOf((byte) phy); } /** * @since 2.2 */ public int getPeriodicAdvertisingInterval() { return this.periodicAdvertisingInterval; } /** * @since 2.2 */ public void setPeriodicAdvertisingInterval(int periodicAdvertisingInterval) { this.periodicAdvertisingInterval = periodicAdvertisingInterval; } public byte[] getReportData() { return this.reportData; } public void setReportData(byte[] reportData) { this.reportData = reportData; } public int getLength() { return this.length; } public void setLength(int length) { this.length = length; } /** * @since 2.2 */ public int getSid() { return this.sid; } /** * @since 2.2 */ public void setSid(int sid) { this.sid = sid; } /** * @since 2.2 */ public int getTxPower() { return this.txPower; } /** * @since 2.2 */ public void setTxPower(int txPower) { this.txPower = txPower; } public int getRssi() { return this.rssi; } public void setRssi(int rssi) { this.rssi = rssi; } /** * @since 2.2 */ public boolean isExtendedReport() { return this.extended; } /** * @since 2.2 */ public void setExtendedReport(boolean extended) { this.extended = extended; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeacon.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeBeacon is a representation of a generic Beacon advertise packet. * * @noextend This class is not intended to be subclassed by clients. * @since 1.3 */ @ProviderType public abstract class BluetoothLeBeacon { public static final byte AD_BYTES_NUMBER = 0x02; public static final byte AD_FLAG = 0x01; private boolean leBrHost; private boolean leBrController; private boolean brEdrSupported; private boolean leGeneral; private boolean leLimited; private String address; private int rssi; public BluetoothLeBeacon() { this.leBrHost = true; this.leBrController = true; this.brEdrSupported = false; this.leGeneral = true; this.leLimited = false; } public boolean isLeBrHost() { return this.leBrHost; } public void setLeBrHost(boolean leBrHost) { this.leBrHost = leBrHost; } public boolean isLeBrController() { return this.leBrController; } public void setLeBrController(boolean leBrController) { this.leBrController = leBrController; } public boolean isBrEdrSupported() { return this.brEdrSupported; } public void setBrEdrSupported(boolean brEdrSupported) { this.brEdrSupported = brEdrSupported; } public boolean isLeGeneral() { return this.leGeneral; } public void setLeGeneral(boolean leGeneral) { this.leGeneral = leGeneral; } public boolean isLeLimited() { return this.leLimited; } public void setLeLimited(boolean leLimited) { this.leLimited = leLimited; } public String getAddress() { return this.address; } public void setAddress(String address) { this.address = address; } public int getRssi() { return this.rssi; } public void setRssi(int rssi) { this.rssi = rssi; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconAdvertiser.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.eclipse.kura.KuraBluetoothCommandException; import org.eclipse.kura.bluetooth.le.BluetoothLeAdapter; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeBeaconAdvertising allows to manage the advertising mechanism for Bluetooth LE beacons. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeBeaconAdvertiser { /** * Start Beacon advertising. * If the advertising has been already started or an error is detected, this method throws a * KuraBluetoothCommandException. * * @throw KuraBluetoothCommandException */ public void startBeaconAdvertising() throws KuraBluetoothCommandException; /** * Stop Beacon advertising. * If the advertising has been already stopped or an error is detected, this method throws a * KuraBluetoothCommandException. * * @throw KuraBluetoothCommandException */ public void stopBeaconAdvertising() throws KuraBluetoothCommandException; /** * Set the minimum and maximum Beacon advertising interval. * Both intervals are computed as Nx0.625 ms, where N can vary from 14 to 65534. * So, the minimum and maximum intervals are in the range 8.75ms - 40.9s. * Note that further limitations can be introduced by the hardware Bluetooth controller. * * @param min * Minimum time interval between advertises * @param max * Maximum time interval between advertises * * @throw KuraBluetoothCommandException */ public void updateBeaconAdvertisingInterval(Integer min, Integer max) throws KuraBluetoothCommandException; /** * Set the data in to the Beacon advertising packet. * * @param beacon * An instance of BluetoothLeBeacon class * * @throw KuraBluetoothCommandException */ public void updateBeaconAdvertisingData(T beacon) throws KuraBluetoothCommandException; /** * Get the bluetooth adapter this advertiser is associated to. * * @return BluetoothLeAdapter */ public BluetoothLeAdapter getAdapter(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconDecoder.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.osgi.annotation.versioning.ConsumerType; /** * BluetoothLeBeaconDecoder provides a way to decode beacons. * * @since 1.3 */ @ConsumerType public interface BluetoothLeBeaconDecoder { /** * Decodes a byte array into a BluetoothLeBeacon object * * @param data * the byte array acquired by a scanner * @return BluetoothLeBeacon */ public T decode(byte[] data); /** * Get the type of beacon this decoder can manage * * @return Class the type of beacon (i.e. BlueoothLeIBeacon) * */ public Class getBeaconType(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.osgi.annotation.versioning.ConsumerType; /** * BluetoothLeBeaconEncoder provides a way to encode beacons. * * @since 1.3 */ @ConsumerType public interface BluetoothLeBeaconEncoder { /** * Encodes a BluetoothLeBeacon into a byte array * * @param beacon * the BluetoothLeBeacon to be broadcast by an advertiser * @return byte[] */ public byte[] encode(T beacon); /** * Get the type of beacon this encoder can manage * * @return Class the type of beacon (i.e. BlueoothLeIBeacon) * */ public Class getBeaconType(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconManager.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.eclipse.kura.KuraBluetoothBeaconAdvertiserNotAvailable; import org.eclipse.kura.bluetooth.le.BluetoothLeAdapter; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeBeaconManager allows the management of specific Bluetooth LE Beacon devices. * It provides beacon scanner and advertiser classes using the given adapter and codecs. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeBeaconManager { /** * Instantiate a new scanner for beacons. * * @param adapter * the bluetooth adapter used by the scanner * @param decoder * the decoder used to parse the data acquired by the scanner * @return BluetoothLeBeaconScanner */ public BluetoothLeBeaconScanner newBeaconScanner(BluetoothLeAdapter adapter, BluetoothLeBeaconDecoder decoder); /** * Instantiate a new advertiser for beacons. * * @param adapter * the bluetooth adapter used by the advertiser * @param encoder * the encoder used to encode the data to be broadcast * @return BluetoothLeBeaconAdvertiser * @throws KuraBluetoothBeaconAdvertiserNotAvailable */ public BluetoothLeBeaconAdvertiser newBeaconAdvertiser(BluetoothLeAdapter adapter, BluetoothLeBeaconEncoder encoder) throws KuraBluetoothBeaconAdvertiserNotAvailable; /** * Delete the given scanner. * * @param scanner * The scanner to be deleted */ public void deleteBeaconScanner(BluetoothLeBeaconScanner scanner); /** * Delete the given advertiser. * * @param advertiser * The advertiser to be deleted */ public void deleteBeaconAdvertiser(BluetoothLeBeaconAdvertiser advertiser); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconScanner.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.eclipse.kura.KuraBluetoothCommandException; import org.eclipse.kura.bluetooth.le.BluetoothLeAdapter; import org.eclipse.kura.bluetooth.le.beacon.listener.BluetoothLeBeaconListener; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeBeaconScanner allows to manage the scanner mechanism for Bluetooth LE beacons. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeBeaconScanner { /** * Start a scan for beacons of given duration in seconds. * * @param duration * The scan duration in seconds * @throws KuraBluetoothCommandException */ public void startBeaconScan(long duration) throws KuraBluetoothCommandException; /** * Stop the scan for beacons. */ public void stopBeaconScan(); /** * Indicates if a scan is running. * * @return */ public boolean isScanning(); /** * Add a listener for detected beacons. * * @param listener * The beacon listener */ public void addBeaconListener(BluetoothLeBeaconListener listener); /** * Remove the given beacon listener * * @param listener * The beacon listener */ public void removeBeaconListener(BluetoothLeBeaconListener listener); /** * Get the bluetooth adapter this advertiser is associated to. * * @return BluetoothLeAdapter */ public BluetoothLeAdapter getAdapter(); /** * Get the decoder used by this scanner. * * @return BluetoothLeBeaconDecoder */ public BluetoothLeBeaconDecoder getDecoder(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/BluetoothLeBeaconService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon; import org.eclipse.kura.KuraBluetoothBeaconAdvertiserNotAvailable; import org.eclipse.kura.bluetooth.le.BluetoothLeAdapter; import org.osgi.annotation.versioning.ProviderType; /** * BluetoothLeBeaconService provides a mechanism for interfacing with specific Bluetooth LE Beacon devices. * It allows to advertise beacon packets and to scan for beacons of the given BluetoothLeBeacon type using the * configured adapter. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.3 */ @ProviderType public interface BluetoothLeBeaconService { /** * Instantiate a new scanner for beacons. * * @param adapter * the bluetooth adapter used by the scanner * @return BluetoothLeBeaconScanner */ public BluetoothLeBeaconScanner newBeaconScanner(BluetoothLeAdapter adapter); /** * Instantiate a new advertiser for beacons. * * @param adapter * the bluetooth adapter used by the advertiser * @return BluetoothLeBeaconAdvertiser * @throws KuraBluetoothBeaconAdvertiserNotAvailable */ public BluetoothLeBeaconAdvertiser newBeaconAdvertiser(BluetoothLeAdapter adapter) throws KuraBluetoothBeaconAdvertiserNotAvailable; /** * Delete the given scanner. * * @param scanner * The scanenr to be deleted */ public void deleteBeaconScanner(BluetoothLeBeaconScanner scanner); /** * Delete the given advertiser. * * @param advertiser * The advertiser to be deleted */ public void deleteBeaconAdvertiser(BluetoothLeBeaconAdvertiser advertiser); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/listener/BluetoothLeBeaconListener.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.bluetooth.le.beacon.listener; import org.eclipse.kura.bluetooth.le.beacon.BluetoothLeBeacon; import org.osgi.annotation.versioning.ConsumerType; /** * BluetoothLeBeaconListener must be implemented by any class wishing to receive BLE beacon data * * @since 1.3 */ @ConsumerType @FunctionalInterface public interface BluetoothLeBeaconListener { /** * Fired when Bluetooth LE beacons data is received * * @param beacon * a received beacon */ public void onBeaconsReceived(T beacon); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains interface to track Bluetooth LE beacon devices. * */ package org.eclipse.kura.bluetooth.le.beacon.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/beacon/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to manage Bluetooth LE beacon devices. * */ package org.eclipse.kura.bluetooth.le.beacon; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/bluetooth/le/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to manage connections to Bluetooth LE devices. * */ package org.eclipse.kura.bluetooth.le; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/CertificatesService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.certificate; import java.security.cert.Certificate; import java.util.Enumeration; import java.util.List; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraApplicationTopic; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ProviderType; /** * The CertificatesService is used to manage the storage, listing and retrieval of public certificates * from a key store. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CertificatesService { /** * The storeCertificate interface method receives a certificate and an alias that should be stored in a key store * * @param cert * The certificate of type Certificate that has to be stored in a key store * @param alias * A string that will be used to identify the certificate in a key store * @throws KuraException * raised if the certificate storage operation failed * @deprecated Since 2.2 use {@link #addCertificate(KuraCertificateEntry)} */ @Deprecated public void storeCertificate(Certificate cert, String alias) throws KuraException; /** * listCACertificatesAliases provides an enumeration of strings representing the different CA certificates * stored in a key store * * @return An enumeration containing the strings that represent the CA aliases stored in a key store. * * @deprecated Since 2.2 use {@link #getCertificateEntry(String)} */ @Deprecated public Enumeration listCACertificatesAliases(); /** * listSSLCertificatesAliases provides an enumeration of strings representing the different ssl certificates * stored in a key store * * @return An enumeration containing the strings that represent the aliases stored in a key store. * * @deprecated Since 2.2 use {@link #getCertificateEntry(String)} */ @Deprecated public Enumeration listSSLCertificatesAliases(); /** * listDMCertificatesAliases provides an enumeration of strings representing the different certificates used to * authenticate * the messages coming from the remote platform and stored in the device key store * * @return An enumeration containing the strings that represent the aliases stored in a key store. * * @deprecated Since 2.2 use {@link #getCertificateEntry(String)} */ @Deprecated public Enumeration listDMCertificatesAliases(); /** * listBundleCertificatesAliases provides an enumeration of strings representing the different certificates used to * sign * the bundles and that are stored in the device key store * * @return An enumeration containing the strings that represent the aliases stored in a key store. * * @deprecated Since 2.2 use {@link #getCertificateEntry(String)} */ @Deprecated public Enumeration listBundleCertificatesAliases(); /** * returnCertificate returns the certificate corresponding to the specified alias. * * @param alias * The string used to identify the certificate in a key store * @return A Certificate object retrieved from a key store. * * @deprecated Since 2.2 use {@link #getCertificateEntry(String)} */ @Deprecated public Certificate returnCertificate(String alias) throws KuraException; /** * removeCertificate tries to remove the specified certificate from the key store. Returns true, if the removal * operation succeeded. False, otherwise. * * @param alias * The string used to identify the certificate in a key store * @throws KuraException * raised if the certificate removal operation failed * * @deprecated Since 2.2 use {@link #deleteCertificate(String)} */ @Deprecated public void removeCertificate(String alias) throws KuraException; /** * verifySignature is a method that takes the topic used * to send the message and the signed message to verify the correctness of the signature. * * @param kuraAppTopic * The application topic part used to send the message * @param kuraPayload * The kuraPayload message received and that needs to be verified * @return A boolean value that is true if the signature received corresponds with the signature * calculated from the message content. False otherwise. * @since 2.0 * */ public boolean verifySignature(KuraApplicationTopic kuraAppTopic, KuraPayload kuraPayload); /** * Return the list of the installed {@KuraCertificate} * * @return a list of {@KuraCertificate} * @throws KuraException * * @since 2.2 */ public List getCertificates() throws KuraException; /** * Return the {@KuraCertificate} identified by its id * * @param id * the id of the certificate * @return the {@KuraCertificate} * @throws KuraException * * @since 2.2 */ public KuraCertificateEntry getCertificateEntry(String id) throws KuraException; /** * Update the {@KuraCertificate} in a keystore * * @param id * the id of the certificate * @param certificate * the new certificate * @throws KuraException * * @since 2.2 */ public void updateCertificate(KuraCertificateEntry certificate) throws KuraException; /** * Add a {@KuraCertificate} in a keystore * * @param certificate * the new certificate * @throws KuraException * * @since 2.2 */ public void addCertificate(KuraCertificateEntry certificate) throws KuraException; /** * Delete the certificate identified by its id * * @param id * the id of the certificate * @throws KuraException * * @since 2.2 */ public void deleteCertificate(String id) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/KuraCertificateEntry.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.certificate; import java.security.KeyStore.TrustedCertificateEntry; import java.security.cert.Certificate; /** * * The KuraCertificateEntry represents a {@java.security.KeyStore.TrustedCertificateEntry} stored in a keystore. * The entry is identified by an id made with the id of the keystore and the alias. * * @since 2.2 */ public class KuraCertificateEntry { private String certificateId; private String keystoreId; private String alias; private TrustedCertificateEntry certificateEntry; public KuraCertificateEntry(String keystoreId, String alias, Certificate certificate) { super(); this.keystoreId = keystoreId; this.alias = alias; this.certificateEntry = new TrustedCertificateEntry(certificate); this.certificateId = keystoreId + ":" + alias; } public KuraCertificateEntry(String keystoreId, String alias, TrustedCertificateEntry entry) { super(); this.keystoreId = keystoreId; this.alias = alias; this.certificateEntry = entry; this.certificateId = keystoreId + ":" + alias; } public String getCertificateId() { return this.certificateId; } public String getKeystoreId() { return this.keystoreId; } public String getAlias() { return this.alias; } public TrustedCertificateEntry getCertificateEntry() { return this.certificateEntry; } public static String getKeystoreId(String id) { if (id != null) { return id.split(":")[0]; } else { return ""; } } public static String getAlias(String id) { if (id != null) { String[] fields = id.split(":"); if (fields.length == 1) { return ""; } return fields[fields.length - 1]; } else { return ""; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/KuraPrivateKeyEntry.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.certificate; import java.security.KeyStore.PrivateKeyEntry; import java.security.PrivateKey; import java.security.cert.Certificate; /** * * The KuraPrivateKeyEntry represents a {@java.security.KeyStore.PrivateKeyEntry} stored in a keystore * along with the its certificate chain. * The private key entry is identified by an id made with the id of the keystore and the alias. * * @since 2.2 */ public class KuraPrivateKeyEntry { private final String privateKeyId; private final String keystoreId; private final String alias; private final PrivateKeyEntry privateKeyEntry; public KuraPrivateKeyEntry(String keystoreId, String alias, PrivateKeyEntry privateKeyEntry) { super(); this.keystoreId = keystoreId; this.alias = alias; this.privateKeyEntry = privateKeyEntry; this.privateKeyId = keystoreId + ":" + alias; } public KuraPrivateKeyEntry(String keystoreId, String alias, PrivateKey privateKey, Certificate[] certificateChain) { super(); this.keystoreId = keystoreId; this.alias = alias; this.privateKeyEntry = new PrivateKeyEntry(privateKey, certificateChain); this.privateKeyId = keystoreId + ":" + alias; } public String getPrivateKeyId() { return this.privateKeyId; } public String getKeystoreId() { return this.keystoreId; } public String getAlias() { return this.alias; } public PrivateKeyEntry getPrivateKey() { return this.privateKeyEntry; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/enrollment/EnrollmentService.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.certificate.enrollment; import java.security.cert.CertStore; import java.security.cert.Certificate; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Provides a list of APIs allowing the system to perform an enrollment in a Certificate Authority * * @since 2.4 */ @ProviderType public interface EnrollmentService { /** * * Perform the enrollment of the system with a configured Certificate Authority. * * @throws KuraException * if it is impossible to enroll the system. */ public void enroll() throws KuraException; /** * Renew the client certificate submitting the certificate previously issued by the CA. * * @throws KuraException * if it is impossible to renew the system certificate */ public void renew() throws KuraException; /** * Renew the client certificate creating a new keypair and a new CSR submitted to the CA. * * @throws KuraException * if it is impossible to renew the system certificate */ public void rekey() throws KuraException; /** * * Get the list of the Certificate Authority certificates stored in the relative * {@link org.eclipse.kura.security.keystore.KeystoreService} * * @return returns the Certificate Authority CertStore * @throws KuraException * if it is impossible to retrieve the certificate store. */ public CertStore getCACertificates() throws KuraException; /** * Get the Client certificate stored in the relative * {@link org.eclipse.kura.security.keystore.KeystoreService} * * @return returns the Client Certificate obtained by the Certificate * Authority * @throws KuraException * if it is impossible to retrieve the certificate. */ public Certificate getClientCertificate() throws KuraException; /** * Force the update of Certificate Authority certificate if a newest is available. * * @throws KuraException * if it is impossible to perform the request to the server. */ public void forceCACertificateRollover() throws KuraException; /** * * Check if the system in enrolled or not, that is the presence or not of the client certificate. * * @return true if the system in enrolled, false otherwise. * @throws KuraException * if it is impossible to query the keystore for the certificate availability. */ public boolean isEnrolled() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/certificate/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Contains interfaces to manage certificates in a key store * */ package org.eclipse.kura.certificate; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/Channel.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import java.util.Objects; import org.eclipse.kura.annotation.NotThreadSafe; import org.eclipse.kura.type.DataType; import org.eclipse.kura.type.TypedValue; import org.osgi.annotation.versioning.ProviderType; /** * The Class Channel represents a communication channel. The * communication channel has all the required configuration to perform specific * operation (read/write). * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @NotThreadSafe @ProviderType public class Channel { private static final String MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL = "Channel configuration cannot be null"; private static final String MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL = "Channel value type cannot be null"; private static final String MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL = "Channel type cannot be null"; private static final String MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL = "Channel name cannot be null"; /** The communication channel configuration. */ private final transient Map configuration; /** The name of the communication channel. */ private String name; /** The type of the channel. (READ/WRITE/READ_WRITE) */ private ChannelType type; /** * The data type of the value as expected from the operation */ private DataType valueType; /** * The data type of the scale/offset as expected from the operation */ private ScaleOffsetType scaleOffsetType = ScaleOffsetType.DEFINED_BY_VALUE_TYPE; /* * The value used to scale the value */ private Number valueScale = 1.0d; /** * The value used as offset of the value */ private Number valueOffset = 0.0d; private String unit = ""; /** * Determines if this channel is enabled or not */ private boolean isEnabled = true; /** * Instantiates a new channel. * * @param name * the name for this channel * @param type * the type * @param valueType * the value type * @param config * the configuration * @throws NullPointerException * if any of the arguments is null * @deprecated Use {@link #Channel(String, ChannelType, DataType, ScaleOffsetType, Number, Number, Map)} */ @Deprecated public Channel(final String name, final ChannelType type, final DataType valueType, final Map config) { requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL); requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL); requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL); requireNonNull(config, MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL); this.configuration = Collections.unmodifiableMap(config); this.name = name; this.type = type; this.valueType = valueType; } /** * Instantiates a new channel. * * @param name * the name for this channel * @param type * the type * @param valueType * the value type * @param valueScale * the value used to scale the value, must have the same {@link DataType} as valueOffset * @param valueOffset * the value used as offset of the value, must have the same {@link DataType} as valueScale * @param config * the configuration * @throws NullPointerException * if any of the arguments is null * @throws IllegalArgumentException * if any of the valueScale and valueOffset have different types * * @since 2.8 */ public Channel(final String name, final ChannelType type, final DataType valueType, final ScaleOffsetType scaleOffsetType, final Number valueScale, final Number valueOffset, final Map config) { requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL); requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL); requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL); requireNonNull(config, MESSAGE_CHANNEL_CONFIGURATION_CANNOT_BE_NULL); requireNonNull(scaleOffsetType, "Scale/Offset type cannot be null"); requireNonNull(valueScale, "Channel value scale cannot be null"); requireNonNull(valueOffset, "Channel value offset cannot be null"); this.configuration = Collections.unmodifiableMap(config); this.name = name; this.type = type; this.valueType = valueType; this.scaleOffsetType = scaleOffsetType; this.valueScale = valueScale; this.valueOffset = valueOffset; } /** * Gets the configuration of the communication channel. * * @return the configuration of the communication channel */ public Map getConfiguration() { return this.configuration; } /** * Gets the name of the communication channel. * * @return the name of the communication channel */ public String getName() { return this.name; } /** * Gets the type of the communication channel. * * @return the type of the communication channel */ public ChannelType getType() { return this.type; } /** * Gets the value type as expected for operations. * * @return the value type */ public DataType getValueType() { return this.valueType; } /** * Gets the Scale/Offset type as expected for operations. * * @return the value type * * @since 2.8 */ public ScaleOffsetType getScaleOffsetType() { return this.scaleOffsetType; } /** * Returns a boolean indicating if this channel is enabled or not * * @since 1.4 * @return a boolean indicating if this channel is enabled or not */ public boolean isEnabled() { return this.isEnabled; } /** * Returns a double that represents the scale factor to be applied to the read value * * @return a double that represents the scale factor to be applied to the read value * * @since 2.3 * * @deprecated Use {@link #getValueScaleAsNumber()} */ @Deprecated public double getValueScale() { return this.valueScale.doubleValue(); } /** * Returns a {@link Number} that represents the scale factor to be applied to the read * value * * @return a {@link Number} that represents the scale factor to be applied to the read value * * @since 2.8 */ public Number getValueScaleAsNumber() { return this.valueScale; } /** * Returns a double that represents the offset to be applied to the read value * * @return a double that represents the offset to be applied to the read value * * @since 2.3 * * @deprecated Use {@link #getValueOffsetAsNumber()} */ @Deprecated public double getValueOffset() { return this.valueOffset.doubleValue(); } /** * Returns a {@link TypedValue} that represents the offset factor to be applied to the read * value * * @return a {@link TypedValue} that represents the offset factor to be applied to the read value * * @since 2.8 */ public Number getValueOffsetAsNumber() { return this.valueOffset; } /** * @since 2.3 */ public String getUnit() { return this.unit; } /** * Sets the name. * * @param name * the new name * @throws NullPointerException * if the argument is null */ public void setName(final String name) { requireNonNull(name, MESSAGE_CHANNEL_NAME_CANNOT_BE_NULL); this.name = name; } /** * Sets the type. * * @param type * the new type * @throws NullPointerException * if the argument is null */ public void setType(final ChannelType type) { requireNonNull(type, MESSAGE_CHANNEL_TYPE_CANNOT_BE_NULL); this.type = type; } /** * Sets the value type. * * @param valueType * the new value type * @throws NullPointerException * if the argument is null */ public void setValueType(final DataType valueType) { requireNonNull(valueType, MESSAGE_CHANNEL_VALUE_TYPE_CANNOT_BE_NULL); this.valueType = valueType; } /** * Set the type of the scale/offset. * * @param scaleOffsetType * the scale/offset type * @throws NullPointerException * if the argument is null * * @since 2.8 */ public void setScaleOffsetType(ScaleOffsetType scaleOffsetType) { requireNonNull(this.valueType, "Scale/Offset value type cannot be null"); this.scaleOffsetType = scaleOffsetType; } /** * Specifies if this channel is enabled or not * * @since 1.4 * @param isEnabled * a boolean indicating if this channel is enabled or not */ public void setEnabled(boolean isEnabled) { this.isEnabled = isEnabled; } /** * Specifies the scale to be applied to the channel value * * @param scale * a double value that specifies the scale to be applied to the channel value * @since 2.3 * @deprecated since version 3.0 */ @Deprecated public void setScale(double scale) { this.valueScale = scale; } /** * Specifies the scale to be applied to the channel value * * @param scale * a {@link Number} value that specifies the scale to be applied to the channel value * @since 2.8 */ public void setScale(Number scale) { this.valueScale = scale; } /** * Specifies the offset to be applied to the channel value * * @param offset * a double value that specifies the offset to be applied to the channel value * @since 2.3 * @deprecated since version 3.0 */ @Deprecated public void setOffset(double offset) { this.valueOffset = offset; } /** * Specifies the offset to be applied to the channel value * * @param offset * a {@link Number} value that specifies the offset to be applied to the channel value * @since 2.8 */ public void setOffset(Number offset) { this.valueOffset = offset; } /** * @since 2.3 */ public void setUnit(String unit) { this.unit = unit; } /** {@inheritDoc} */ @Override public String toString() { return "Channel [configuration=" + this.configuration + ", name=" + this.name + ", type=" + this.type + ", valueType=" + this.valueType + ", valueScale=" + this.valueScale + ", valueOffset=" + this.valueOffset + ", valueType=" + this.valueType + ", unit=" + this.unit + "]"; } /** * Creates a new {@link ChannelRecord} that represents a read request * for the value of this {@code Channel}. * * @return * the {@link ChannelRecord} */ public ChannelRecord createReadRecord() { ChannelRecord result = ChannelRecord.createReadRecord(this.name, this.valueType, this.unit); result.setChannelConfig(this.configuration); return result; } /** * Creates a new {@link ChannelRecord} that represents a write request for this * {@code Channel}. * * @param vlaue * The value to be written. * @throws IllegalArgumentException * If the {@link DataType} of the provided value differs from the data type * of this channel * @throws NullPointerException * If the provided value is null * @return * the {@link CheannelRecord} */ public ChannelRecord createWriteRecord(TypedValue value) { requireNonNull(value, "Value cannot be null"); if (value.getType() != this.valueType) { throw new IllegalArgumentException("The value type of the argument must match the channel value type"); } ChannelRecord result = ChannelRecord.createWriteRecord(this.name, value); result.setChannelConfig(this.configuration); return result; } @Override public int hashCode() { return Objects.hash(this.isEnabled, this.name, this.scaleOffsetType, this.type, this.unit, this.valueOffset, this.valueScale, this.valueType); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if ((obj == null) || (getClass() != obj.getClass())) { return false; } Channel other = (Channel) obj; return this.isEnabled == other.isEnabled && Objects.equals(this.name, other.name) && this.scaleOffsetType == other.scaleOffsetType && this.type == other.type && Objects.equals(this.unit, other.unit) && Objects.equals(this.valueOffset, other.valueOffset) && Objects.equals(this.valueScale, other.valueScale) && this.valueType == other.valueType; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelFlag.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel; /** * This represents all the Channel specific flag codes * * @since 1.2 */ public enum ChannelFlag { /** * In case of any failure on the channel */ FAILURE, /** * In case of successful operation on channel */ SUCCESS } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelRecord.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel; import static java.util.Objects.requireNonNull; import java.util.HashMap; import java.util.Map; import org.eclipse.kura.annotation.NotThreadSafe; import org.eclipse.kura.type.DataType; import org.eclipse.kura.type.TypedValue; import org.osgi.annotation.versioning.ProviderType; /** * The Class ChannelRecord contains the information needed for performing a read or write * operation on a specific channel.
*
* * The possible cases for a channel record are the following: *

    * *
  • * Describing a read request: in this case the channel record must contain the channel * name and the data type to be read. * A channel record suitable for this use case can be created using the * {@link ChannelRecord#createReadRecord(String, DataType)} or {@link Channel#createReadRecord()} methods. *
  • * *
  • * Describing a write request: in this case the channel record must contain the channel * name, the value to be written and its data type * A channel record suitable for this use case can be created using the * {@link ChannelRecord#createWriteRecord(String, TypedValue)} or {@link Channel#createWriteRecord(TypedValue)} methods. *
  • * *
  • * Reporting a status: in this case the channel record must contain the channel * name and a {@link ChannelStatus} instance. * The status contains a flag, an exception message and an exception * instance. * A channel record suitable for this use case can be created using the * {@link ChannelRecord#createStatusRecord(String, ChannelStatus)} method. *
  • * *
* * A channel record might also contain an user defined configuration, specified * as a {@code Map} instance. * This configuration can be used to provide additional information concerning the * operation to be performed. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @ProviderType @NotThreadSafe public class ChannelRecord { private static final String NULL_CHANNEL_NAME_ERROR_MESSAGE = "Channel Name cannot be null"; /** * Provided channel configuration to perform read or write * operation. */ private transient Map channelConfiguration; /** * Represents a channel specific status which signifies the status * of an operation performed on a channel. */ private ChannelStatus channelStatus; /** * Represents the name of this channel */ private String name; /** * Represents the type of the value involved in the read/write operation. */ private DataType valueType; /** * Represents the value obtained/to be written from/to the channel */ private TypedValue value; /** Represents the timestamp of the operation performed. */ private long timestamp; private String unit; private ChannelRecord() { } /** * Creates a channel record that represents a read request. * * @param channelName * The name of the channel * @param valueType * The type of the value to be read * @throws NullPointerException * If any of the provided arguments is null * @return the channel record */ public static ChannelRecord createReadRecord(final String channelName, final DataType valueType) { requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE); requireNonNull(valueType, "Value Type cannot be null"); ChannelRecord result = new ChannelRecord(); result.name = channelName; result.valueType = valueType; result.unit = ""; return result; } /** * @since 2.3 */ public static ChannelRecord createReadRecord(final String channelName, final DataType valueType, final String unit) { requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE); requireNonNull(valueType, "Value Type cannot be null"); ChannelRecord result = new ChannelRecord(); result.name = channelName; result.valueType = valueType; result.unit = unit; return result; } /** * Creates a channel record that represents a write request. * * @param channelName * The name of the channel * @param value * The value to be written * @throws NullPointerException * If any of the provided arguments is null * @return the channel record */ public static ChannelRecord createWriteRecord(final String channelName, final TypedValue value) { requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE); requireNonNull(value, "Value cannot be null"); ChannelRecord result = new ChannelRecord(); result.name = channelName; result.valueType = value.getType(); result.value = value; return result; } /** * Creates a channel record that describes the status of an operation. * * @param channelName * The name of the channel * @param status * The status * @throws NullPointerException * If any of the provided arguments is null * @return the channel record */ public static ChannelRecord createStatusRecord(final String channelName, final ChannelStatus status) { requireNonNull(channelName, NULL_CHANNEL_NAME_ERROR_MESSAGE); requireNonNull(status, "Status cannot be null"); ChannelRecord result = new ChannelRecord(); result.name = channelName; result.channelStatus = status; return result; } /** * Returns the channel configuration as provided. * * @return the channel configuration */ public Map getChannelConfig() { return this.channelConfiguration; } /** * Returns the channel operation status. * * @return the driver status */ public ChannelStatus getChannelStatus() { return this.channelStatus; } /** * Returns the associated timestamp. * * @return the timestamp */ public long getTimestamp() { return this.timestamp; } /** * @since 2.3 */ public String getUnit() { return this.unit; } /** * Sets the channel configuration as provided. * * @param channelConfig * the channel configuration * @throws NullPointerException * if the argument is null */ public void setChannelConfig(final Map channelConfig) { requireNonNull(channelConfig, "Channel configuration cannot be null"); this.channelConfiguration = new HashMap<>(channelConfig); } /** * Sets the status. * * @param status * the new driver status * @throws NullPointerException * if the argument is null */ public void setChannelStatus(final ChannelStatus status) { requireNonNull(status, "Channel Status cannot be null"); this.channelStatus = status; } /** * Sets the timestamp as provided. * * @param timestamp * the new timestamp */ public void setTimestamp(final long timestamp) { this.timestamp = timestamp; } /** * @since 2.3 */ public void setUnit(final String unit) { this.unit = unit; } /** * Returns the name of the channel associated to the operation represented by this channel record * * @return the channel name */ public String getChannelName() { return this.name; } /** * Returns the type of the value associated to the operation represented by this channel record * * @return the value type */ public DataType getValueType() { return this.valueType; } /** * Returns the value associated to the operation represented by this channel record * * @return the value */ public TypedValue getValue() { return this.value; } /** * Sets the value associated to the operation represented by this channel record * * @param value * the value to be set * @throws NullPointerException * if the provided value is null */ public void setValue(TypedValue value) { requireNonNull(value, "Value cannot be null"); this.value = value; } @Override public String toString() { return "ChannelRecord [channelConfiguration=" + this.channelConfiguration + ", channelStatus=" + this.channelStatus + ", name=" + this.name + ", valueType=" + this.valueType + ", value=" + this.value + ", timestamp=" + this.timestamp + ", unit=" + this.unit + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.channelStatus == null ? 0 : this.channelStatus.hashCode()); result = prime * result + (this.name == null ? 0 : this.name.hashCode()); result = prime * result + (int) (this.timestamp ^ this.timestamp >>> 32); result = prime * result + (this.unit == null ? 0 : this.unit.hashCode()); result = prime * result + (this.value == null ? 0 : this.value.hashCode()); result = prime * result + (this.valueType == null ? 0 : this.valueType.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } ChannelRecord other = (ChannelRecord) obj; if (this.channelStatus == null) { if (other.channelStatus != null) { return false; } } else if (!this.channelStatus.equals(other.channelStatus)) { return false; } if (this.name == null) { if (other.name != null) { return false; } } else if (!this.name.equals(other.name)) { return false; } if (this.timestamp != other.timestamp) { return false; } if (this.unit == null) { if (other.unit != null) { return false; } } else if (!this.unit.equals(other.unit)) { return false; } if (this.value == null) { if (other.value != null) { return false; } } else if (!this.value.equals(other.value)) { return false; } if (this.valueType != other.valueType) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelStatus.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel; import static java.util.Objects.requireNonNull; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.Nullable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * The Class ChannelStatus is responsible for representing the status of any * channel specific operation * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class ChannelStatus { /** The channel flag. */ private final ChannelFlag channelFlag; /** The exception instance if needed. */ @Nullable private final Exception exception; /** The exception Message. */ @Nullable private final String exceptionMessage; /** * Instantiates a new status. * * @param channelFlag * the channel flag * @throws NullPointerException * if the channel flag is null */ public ChannelStatus(final ChannelFlag channelFlag) { requireNonNull(channelFlag, "Channel Flag cannot be null"); this.channelFlag = channelFlag; this.exceptionMessage = null; this.exception = null; } /** * Instantiates a new status. * * @param channelFlag * the channel flag * @param exceptionMessage * the exception message * @param exception * the exception * @throws NullPointerException * if the channel flag is null */ public ChannelStatus(final ChannelFlag channelFlag, @Nullable final String exceptionMessage, @Nullable final Exception exception) { requireNonNull(channelFlag, "Driver Flag cannot be null"); this.channelFlag = channelFlag; this.exceptionMessage = exceptionMessage; this.exception = exception; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final ChannelStatus other = (ChannelStatus) obj; if (this.channelFlag != other.channelFlag) { return false; } if (this.exception == null) { if (other.exception != null) { return false; } } else if (!this.exception.equals(other.exception)) { return false; } if (this.exceptionMessage == null) { if (other.exceptionMessage != null) { return false; } } else if (!this.exceptionMessage.equals(other.exceptionMessage)) { return false; } return true; } /** * Gets the channel flag. * * @return the channel flag */ public ChannelFlag getChannelFlag() { return this.channelFlag; } /** * Gets the exception. * * @return the exception */ public Exception getException() { return this.exception; } /** * Gets the exception message. * * @return the exception message */ public String getExceptionMessage() { return this.exceptionMessage; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.channelFlag == null ? 0 : this.channelFlag.hashCode()); result = prime * result + (this.exception == null ? 0 : this.exception.hashCode()); result = prime * result + (this.exceptionMessage == null ? 0 : this.exceptionMessage.hashCode()); return result; } @Override public String toString() { return "ChannelStatus [channelFlag=" + this.channelFlag + ", exception=" + this.exception + ", exceptionMessage=" + this.exceptionMessage + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ChannelType.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel; /** * This provides the necessary constants to denote the type of the channel * (whether the channel is for reading or writing or both) * * @since 1.2 */ public enum ChannelType { /** * The channel will be used for performing reading operation */ READ, /** * The channel will be used for performing both reading and writing * operations */ READ_WRITE, /** * The channel will be used for performing writing operation */ WRITE; /** * Converts {@code channelTypeString}, if possible, to the related {@link ChannelType}. * * @param channelTypeString * String that we want to use to get the respective {@link ChannelType}. * @return a ChannelType that corresponds to the String passed as argument. * @throws IllegalArgumentException * if the passed string does not correspond to an existing {@link ChannelType}. */ public static ChannelType getChannelType(String channelTypeString) { if (READ.name().equalsIgnoreCase(channelTypeString)) { return READ; } if (WRITE.name().equalsIgnoreCase(channelTypeString)) { return WRITE; } if (READ_WRITE.name().equalsIgnoreCase(channelTypeString)) { return READ_WRITE; } throw new IllegalArgumentException("Cannot convert to ChannelType"); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/ScaleOffsetType.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.channel; /** * This contains all the required type constants for representing * Scale and Offset. * * @since 2.8 */ public enum ScaleOffsetType { DEFINED_BY_VALUE_TYPE, /** * @since 3.0 */ FLOAT, DOUBLE, /** * @since 3.0 */ INTEGER, LONG; /** * Converts {@code stringScaleOffsetType}, if possible, to the related {@link ScaleOffsetType}. * * @param stringDataType * String that we want to use to get the respective {@link ScaleOffsetType}. * @return a ScaleOffsetType that corresponds to the String passed as argument. * @throws IllegalArgumentException * if the passed string does not correspond to an existing {@link ScaleOffsetType}. */ public static ScaleOffsetType getScaleOffsetType(String stringScaleOffsetType) { if (DEFINED_BY_VALUE_TYPE.name().equalsIgnoreCase(stringScaleOffsetType)) { return DEFINED_BY_VALUE_TYPE; } if (FLOAT.name().equalsIgnoreCase(stringScaleOffsetType)) { return FLOAT; } if (DOUBLE.name().equalsIgnoreCase(stringScaleOffsetType)) { return DOUBLE; } if (INTEGER.name().equalsIgnoreCase(stringScaleOffsetType)) { return INTEGER; } if (LONG.name().equalsIgnoreCase(stringScaleOffsetType)) { return LONG; } throw new IllegalArgumentException("Cannot convert to ScaleOffsetType"); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/ChannelEvent.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel.listener; import static java.util.Objects.requireNonNull; import org.eclipse.kura.annotation.NotThreadSafe; import org.eclipse.kura.channel.ChannelRecord; import org.osgi.annotation.versioning.ProviderType; /** * This class represents an event occurred while monitoring specific channel * configuration * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @NotThreadSafe @ProviderType public class ChannelEvent { /** * Represents the channel record as triggered due to the asset specific * monitor operation */ private final ChannelRecord channelRecord; /** * Instantiates a new channel event. * * @param channelRecord * the channel record * @throws NullPointerException * if the argument is null */ public ChannelEvent(final ChannelRecord channelRecord) { requireNonNull(channelRecord, "Channel record cannot be null"); this.channelRecord = channelRecord; } /** * Returns the associated channel record. * * @return the channel record */ public ChannelRecord getChannelRecord() { return this.channelRecord; } /** {@inheritDoc} */ @Override public String toString() { return "ChannelEvent [channeRecord=" + this.channelRecord + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/ChannelListener.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.channel.listener; import org.osgi.annotation.versioning.ConsumerType; /** * The listener interface ChannelListener is mainly for receiving channel events. * The class that is interested in processing a channel event implements this * interface. * * @see ChannelEvent * @since 1.2 */ @FunctionalInterface @ConsumerType public interface ChannelListener { /** * Triggers on channel event * * @param event * the fired channel event * @throws NullPointerException * if event is null */ public void onChannelEvent(ChannelEvent event); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ /** * Provides the Kura Channel Listener API * * @since 1.2 */ package org.eclipse.kura.channel.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/channel/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ /** * Provides the Kura Channel API * * @since 1.2 */ package org.eclipse.kura.channel; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/ClockEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.clock; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * ClockEvent is raised when a clock synchronization has been performed. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ClockEvent extends Event { /** Topic of the ClockEvent */ public static final String CLOCK_EVENT_TOPIC = "org/eclipse/kura/clock"; public ClockEvent(Map properties) { super(CLOCK_EVENT_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/ClockService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.clock; import java.util.Date; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * The ClockService is used to configure how to sych the hardware clock with a remote network service. * The service reports when the clock has been synchronized last and raises an event when it is synchronized. * The ClockService is configurable to determine how the clock synchronization should happen. * By default, the ClockService can be configured to set the time through a Java NTP Client. * It can also be extended to synchronize the clock through a native Linux NTPD service, * using the clock acquired from a GPS signal provided by the Position Service, or * through the a cellular carrier. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ClockService { /** * Returns a Date denoting when the clock was synchronized last. If the clock has * not yet synchronized since Kura started, null is returned. * * @return Date that the clock was last synchronized, null if not synchronized yet. */ public Date getLastSync() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/clock/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains interface and event model to synchronize hardware clock. * */ package org.eclipse.kura.clock; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudCallService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.KuraTimeoutException; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.osgi.annotation.versioning.ProviderType; /** * The CloudCallService provides helper methods to make a request/response conversation with the remote server. * The call methods deal with the logic required to build request messages and track the corresponding responses. * All call methods are synchronous; after a request is issued, the implementation will wait for the response * to arrive or a timeout occurs. The timeout interval used by the service is configurable as a property * of the {@link org.eclipse.kura.data.DataTransportService}. * * @noimplement This interface is not intended to be implemented by clients. * @deprecated */ @ProviderType @Deprecated public interface CloudCallService { /** * Sends a local (to this device) request to a Cloudlet application * with the given application ID waiting for the response. * * @param appId * @param appTopic * @param appPayload * the application specific payload of an KuraRequestPayload. * @param timeout * @return * @throws KuraConnectException * @throws KuraTimeoutException * @throws KuraStoreException * @throws KuraException */ public KuraResponsePayload call(String appId, String appTopic, KuraPayload appPayload, int timeout) throws KuraConnectException, KuraTimeoutException, KuraStoreException, KuraException; /** * Sends a request to a remote server or device identified by the specified deviceId * and targeting the given application ID waiting for the response. * * @param deviceId * @param appId * @param appTopic * @param appPayload * @param timeout * @return * @throws KuraConnectException * @throws KuraTimeoutException * @throws KuraStoreException * @throws KuraException */ public KuraResponsePayload call(String deviceId, String appId, String appTopic, KuraPayload appPayload, int timeout) throws KuraConnectException, KuraTimeoutException, KuraStoreException, KuraException; /** * Returns true if the underlying {@link org.eclipse.kura.data.DataService} is currently connected to the remote server. * * @return */ public boolean isConnected(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudClient.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import java.util.List; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ProviderType; /** * The CloudClient is designed to be used by single application bundles. * CloudClient instances are acquired from the CloudService and they * are released when the work is completed. Generally, a CloudClient * is acquired during the activation phase of a bundle and it is released * during the deactivation phase. *
* CloudClient leverages the {@link org.eclipse.kura.data.DataService} * for all interactions with the transport layer and the communication * with the remote server. CloudClient establishes a set of default * subscriptions that allow remote servers or other devices to direct messages * to the application instance. *
* If the bundle using the CloudClient relies on custom subscriptions * beyond the default ones, it is responsibility of the application to implement * the {@link CloudClientListener#onConnectionEstablished()} callback method in the * CloudCallbackHandler to restore the subscriptions it needs. *
* The CloudClient.release method will unsubscribe all subscriptions * incurred by this client and it will unregister this CloudClient * instance from the list of CloudCallbackHandlers registered. *
* There can be more than one instance of CloudClient in the system, * ideally one per ApplicationId but this is not enforced. * The class accepts more than one callback handler; all registered handlers are invoked * when a message is received. It is up to the received to analyze the topic * of the message received and handle it appropriately. *
* The CloudClient publishes and receives messages using a topic namespace * following a structure as: [CRTL_PREFIX/]accountName/deviceId/appId/appTopic.
*
    *
  • CRTL_PREFIX: is an optional prefix to denote topic used for control messages * as opposed to data messages. The framework makes use of control topics to * separate management messages like replies from those used for application data. *
  • accountName: an unique identifier that represents a group of devices and users *
  • deviceId: an unique identifier within an account that represents a single gateway device. * By default, the MAC address of its primary network interface is generally used as the deviceId of the gateway. * In the case of an MQTT transport, for example, deviceId maps to the Client Identifier (Client ID). *
  • appId: an identifier to denote an application running on the gateway device. * We suggest to version the application identifier in order to allow multiple versions of the application * to coexist, e.g. CONF-V1, CONF-V2, etc. *
  • appTopic topic defined and managed by the application. *
* accountName, deviceId, and applicationId are derived based on the configuration parameters * of the system where this instance is deployed while the applicationTopic is controlled * by the application. The following is an example of topic used for publishing where the prefix * used for the control Topics is $EDC. *
    *
  • publish: accountName/deviceId/applicationId/appTopic *
  • controlPublish: $EDC/accountName/assetId/applicationId/appTopic *
  • subscribe: accountName/deviceId/applicationId/appTopic *
  • controlSubscribe: $EDC/accountName/deviceId/applicationId/appTopic *
  • default subscriptions: $EDC/accountName/deviceId/applicationId/# *
* Note that the default subscription of a CloudClient allows remote servers * or applications running on other devices to publish messages addressed * to specific applications running on specific devices. * * @noimplement This interface is not intended to be implemented by clients. * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} and * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} */ @ProviderType @Deprecated public interface CloudClient { /** * Returns the applicationId of this CloudClient * * @return applicationId */ public String getApplicationId(); /** * Releases this CloudClient handle. This instance should no longer be used. * Note: CloudClient does not unsubscribes all subscriptions incurred by this client, * this responsibility is left to the application developer */ public void release(); /** * Returns an indication of whether the connection to the remote server is established. * If your application needs to manage the connection directly, it can use the * {@link org.eclipse.kura.data.DataService#connect} and {@link org.eclipse.kura.data.DataService#disconnect} methods. * * @return boolean, whether connection to broker is established. */ public boolean isConnected(); /** * Publishes a message to the remote server using the default priority 5. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. It is also responsible to * encode the {@link KuraPayload} payload into binary format. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. * * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int publish(String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException; /** * Publishes a message to the remote server using the default priority 5. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. It is also responsible to * encode the {@link KuraPayload} payload into binary format. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. * @since 1.2 */ public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException; /** * Publishes a message to the remote server. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. It is also responsible to * encode the {@link KuraPayload} payload into binary format. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int publish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a message to the remote server. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. It is also responsible to * encode the {@link KuraPayload} payload into binary format. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. * @since 1.2 */ public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a message to the remote server with a raw byte array payload. * This is the lowest level publish API exposed by the CloudClient. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * Binary payload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int publish(String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a message to the remote server with a raw byte array payload. * This is the lowest level publish API exposed by the CloudClient. * Before passing the message the to {@link org.eclipse.kura.data.DataService}, * the CloudClient will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning and device identification. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String specifying the application portion of the topic the message is published on. * @param payload * Binary payload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. * @since 1.2 */ public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a control message to the remote server. Control messages are qualified with an * additional prefix appended at the beginning of the target topic. The * prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended * automatically by this controlPublish method. Just as {@link #publish}, the * controlPublish method will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning including device identification and encode * the {@link KuraPayload} payload into binary format. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param appTopic * A String specifying the application topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int controlPublish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a control message to the remote server addressing it to another device. * Control messages are qualified with an additional prefix appended at the beginning of the target topic. * The prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended * automatically by this controlPublish method. Just as {@link #publish}, the * controlPublish method will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning including device identification and encode * the {@link KuraPayload} payload into binary format. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String specifying the application topic the message is published on. * @param payload * An KuraPayload representing the message to be published * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int controlPublish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException; /** * Publishes a control message to the remote server addressing it to another device * with a raw byte array payload. * Control messages are qualified with an additional prefix appended at the beginning of the target topic. * The prefix is configured as a property of the {@link org.eclipse.kura.data.DataService} and it appended * automatically by this controlPublish method. Just as {@link #publish}, the * controlPublish method will manipulate the provided topic by appending the necessary parts * to achieve topic partitioning including device identification. *
* The priority argument can be used to control the relative ordering of this * message with other messages that may be currently queued for publishing. * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. Life-cycle messages * (e.g. device start and stop) are an example of messages that are * published by the framework with priority 0. * Priority 1 messages are used by the framework to publish response messages * in request/response conversations to prevent a timeout at the requester. * Application should consider using priority 5 or higher. *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String specifying the application topic the message is published on. * @param payload * Binary payload representing the message to be published. * @param qos * An integer specifying the quality of service the message was published on. * @param retain * Whether or not the broker should retain the message. * @param priority * Relative ordering of this message with other messages that may be currently queued for publishing. * @return The published message's ID. * @throws KuraException * if one of the message composition or message publishing operation fails. */ public int controlPublish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException; /** * Subscribes to a topic with the remote server. The topic is specified as a String * object and the QoS is specified as an integer. The CloudClient will manipulate the * provided topic by appending the necessary parts to achieve topic partitioning and * device identification.
* This is a synchronous call. If the subscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param appTopic * A String object containing the application topic. * @param qos * An int containing the Quality of Service. * @throws KuraException * if the subscription fails. */ public void subscribe(String appTopic, int qos) throws KuraException; /** * Subscribes to a topic with the remote server. The topic is specified by two StringS: one characterizing the * deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and * device identification.
* This is a synchronous call. If the subscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String object containing the application topic. * @param qos * An int containing the Quality of Service. * @throws KuraException * if the subscription fails. * @since 1.2 */ public void subscribe(String deviceId, String appTopic, int qos) throws KuraException; /** * Subscribes to a control topic with the remote server. The topic is specified as a String * object and the QoS is specified as an integer. The CloudClient will manipulate the * provided topic by appending the necessary parts to achieve topic partitioning and * including control prefix and device identification.
* This is a synchronous call. If the subscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param appTopic * A String object containing the application topic. * @param qos * An int containing the Quality of Service. * @throws KuraException * if the subscription fails. */ public void controlSubscribe(String appTopic, int qos) throws KuraException; /** * Subscribes to a control topic with the remote server. The topic is specified by two StringS: one characterizing * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and * including control prefix and device identification.
* This is a synchronous call. If the subscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String object containing the application topic. * @param qos * An int containing the Quality of Service. * @throws KuraException * if the subscription fails. * @since 1.2 */ public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException; /** * Unubscribes to a topic with the remote server. The topic is specified as a String * object and the QoS is specified as an integer. The CloudClient will manipulate the * provided topic by appending the necessary parts to achieve topic partitioning and * device identification.
* This is a synchronous call. If the unsubscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param appTopic * A String object containing the application topic. * @throws KuraException * if the unsubscription fails. */ public void unsubscribe(String appTopic) throws KuraException; /** * Unubscribes to a topic with the remote server. The topic is specified by two StringS: one characterizing * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and * device identification.
* This is a synchronous call. If the unsubscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String object containing the application topic. * @throws KuraException * if the unsubscription fails. * @since 1.2 */ public void unsubscribe(String deviceId, String appTopic) throws KuraException; /** * Unsubscribes to a control topic with the remote server. The topic is specified as a String * object and the QoS is specified as an integer. The CloudClient will manipulate the * provided topic by appending the necessary parts to achieve topic partitioning and * including control prefix and device identification.
* This is a synchronous call. If the unsubscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param appTopic * A String object containing the application topic. * @throws KuraException * if the unsubscription fails. */ public void controlUnsubscribe(String appTopic) throws KuraException; /** * Unsubscribes to a control topic with the remote server. The topic is specified by two StringS: one characterizing * the deviceId and the other representing the appTopic. The QoS is specified as an integer. The CloudClient will * manipulate the provided topic by appending the necessary parts to achieve topic partitioning and * including control prefix and device identification.
* This is a synchronous call. If the unsubscribe fails, an exception will be thrown * that will contain information about the cause of the failure. * * @param deviceId * A String specifying the device ID. * @param appTopic * A String object containing the application topic. * @throws KuraException * if the unsubscription fails. * @since 1.2 */ public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException; /** * Adds a CloudCallbackHandler with this CloudClient. This handler * will receive events when a client publication has arrived, and * when a publish has been fully acknowledged by the remote server. * * @param cloudClientListener * An implementation of the CloudCallbackHandler interface. */ public void addCloudClientListener(CloudClientListener cloudClientListener); /** * Removes a CloudCallbackHandler from this CloudClient. * The provided CloudCallbackHandler will no longer receive the events * when a published message is received. */ public void removeCloudClientListener(CloudClientListener cloudClientListener); /** * Gets the list of identifiers of messages that have not been published yet. * * @return a list of integers. * @throws KuraException * if the operation fails. */ List getUnpublishedMessageIds() throws KuraException; /** * Finds the list of identifiers of messages that are still in-flight * (messages published but not confirmed yet). * This only applies to messages published with QoS > 0. * * @return a list of integers. * @throws KuraException * if the operation fails. */ List getInFlightMessageIds() throws KuraException; /** * Finds the list of identifiers of in-flight messages that have been dropped. * This only applies to messages published with QoS > 0. * On the establishment of a new connection, the service can be configured * either to republish or drop in-flight messages. * The former option can be used if service users tolerate publishing message * duplicates. * The latter option can be used it service users tolerate losing messages. * * @return a list of integers. * @throws KuraException * if the operation fails. */ List getDroppedInFlightMessageIds() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudClientListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ConsumerType; /** * CloudClientListener is the interface to be implemented by applications that needs to be notified of events in the * {@link CloudClient}. * Arrived methods are invoked whenever a message is sent to a appTopic associated to the CloudClient. * The Arrived method signatures are differentiated based on whether the incoming messages have been * published to a data topic (by default accountName/#) or a control topic (by default $EDC/accountName/#). * * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.listener.CloudConnectionListener} and * {@link org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener} instead */ @ConsumerType @Deprecated public interface CloudClientListener { /** * Called by the CloudClient when it receives a published control message from the broker. * If the message received has a binary payload that it has NOT been encoded using the * the KuraPayload class, the received bytes will be set as the body field of a new * KuraPaylaod instance which is passed to the callback Listener interface. * * @param deviceId * The deviceId this message was addressed to. * @param appTopic * The appTopic the message arrived on. * @param msg * The KuraPayload that arrived. * @param qos * The Quality of Service that the message was received on. * @param retain * Whether the message was retained by the broker. */ void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain); /** * Called by the client when it receives a published data message from the broker. * If the message received has a binary payload that it has NOT been encoded using the * the KuraPayload class, the received bytes will be set as the body field of a new * KuraPaylaod instance which is passed to the callback Listener interface. * * @param deviceId * The asset ID of the semanticTopic prefix the message arrived on. * @param appTopic * The appTopic the message arrived on. * @param msg * The KuraPayload that arrived. * @param qos * The Quality of Service that the message was received on. * @param retain * Whether the message was retained by the broker. */ void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain); /** * Called when the client has lost its connection with the broker. Depending on the {@link org.eclipse.kura.data.DataService} * configuration, the client will attempt to reconnect and call the * {@link CloudClientListener#onConnectionEstablished} * method upon a successful reconnect. This is only a notification, the callback handler should * not attempt to handle the reconnect. *
* If the bundle using the client relies on subscriptions beyond the default ones, * it is responsibility of the application to implement the {@link CloudClientListener#onConnectionEstablished} * callback method to restore the subscriptions it needs after a connection loss. */ void onConnectionLost(); /** * Called when the CloudClient has successfully connected with the broker. *
* If the bundle using the client relies on subscriptions beyond the default ones, * it is responsibility of the application to implement the {@link CloudClientListener#onConnectionEstablished} * callback method to restore the subscriptions it needs after a connection loss. */ void onConnectionEstablished(); /** * Called by the CloudClient when a published message has been fully acknowledged by the broker, * as appropriate for the quality of service. The published method is not called for QoS 0 publications. * * @param messageId * The message id of the published message */ void onMessageConfirmed(int messageId, String appTopic); /** * Called by the CloudClient when a message has been transfered from the publishing queue * to the underlying {@link org.eclipse.kura.data.DataTransportService} for publishing on the wire. */ void onMessagePublished(int messageId, String appTopic); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudConnectionEstablishedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * CloudConnectionEstablishedEvent is raised with the Cloud Connection is established. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class CloudConnectionEstablishedEvent extends Event { /** Topic of the CloudConnectionEstablishedEvent */ public static final String CLOUD_CONNECTION_STATUS_ESTABLISHED = "org/eclipse/kura/cloud/CloudConnectionStatus/ESTABLISHED"; public CloudConnectionEstablishedEvent(Map properties) { super(CLOUD_CONNECTION_STATUS_ESTABLISHED, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudConnectionLostEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * CloudConnectionEstablishedEvent is raised with the Cloud Connection is lost. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class CloudConnectionLostEvent extends Event { /** Topic of the CloudConnectionLostEvent */ public static final String CLOUD_CONNECTION_STATUS_LOST = "org/eclipse/kura/cloud/CloudConnectionStatus/LOST"; public CloudConnectionLostEvent(Map properties) { super(CLOUD_CONNECTION_STATUS_LOST, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadEncoding.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloud; /** * This enum specifies the supported payload encodings. * * @since 1.2 */ public enum CloudPayloadEncoding { KURA_PROTOBUF("kura-protobuf"), SIMPLE_JSON("simple-json"); private final String encodingText; private CloudPayloadEncoding(String encoding) { this.encodingText = encoding; } /** * Allows to map a provided string with the corresponding {@link CloudPayloadEncoding} * * @param proposedEncoding * the String that has to be mapped to the corresponding {@link CloudPayloadEncoding} * @return {@link CloudPayloadEncoding} if the matching between passed string and enum values succeeds * @throws IllegalArgumentException * if the argument cannot be matched to a corresponding {@link CloudPayloadEncoding} object. */ public static CloudPayloadEncoding getEncoding(String proposedEncoding) { for (CloudPayloadEncoding encoding : CloudPayloadEncoding.values()) { if (encoding.encodingText.equalsIgnoreCase(proposedEncoding)) { return encoding; } } throw new IllegalArgumentException("Unsupported Encoding!"); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadProtoBufDecoder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudPayloadProtoBufDecoder { /** * Decodes a Google Protocol Buffers encoded, optionally gzipped, binary payload to a * {@link org.eclipse.kura.message.KuraPayload}. * * @param payload * @return * @throws KuraException */ public KuraPayload buildFromByteArray(byte[] payload) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudPayloadProtoBufEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudPayloadProtoBufEncoder { /** * Encodes a {@link org.eclipse.kura.message.KuraPayload} to a Google Protocol Buffers encoded, optionally gzipped, * binary payload. * * @param kuraPayload * @param gzipped * @return * @throws KuraException */ byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * The CloudService provides an easy to use API layer for M2M application to communicate with a remote server. * It operates as a decorator for the {@link org.eclipse.kura.data.DataService} providing add-on * features over the management of the transport layer. * In addition to simple publish/subscribe, the Cloud Service API simplifies the implementation of more complex * interaction flows like request/response or remote resource management. Cloud Service abstracts the * developers from the complexity of the transport protocol and payload format used in the communication.
* CloudService allows for a single connection to a remote server to be shared across more than one application * in the gateway providing the necessary topic partitioning.
* Its responsibilities can be summarized as: *
    *
  • Adds application topic prefixes to allow for a single remote server connection to be shared across applications *
  • Define a payload data model and provide default encoding/decoding serializers *
  • Publish life-cycle messages when device and applications start and stop *
* The CloudService can be used through the {@link CloudClient} API or by extending the {@link Cloudlet} class. * {@link Cloudlet} simplifies the interactions with remote servers providing a servlet-like API * to implement request and response flows and remote resource management. * * @noimplement This interface is not intended to be implemented by clients. * * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.CloudConnectionManager} */ @ProviderType @Deprecated public interface CloudService { /** * Returns a new instance of the CloudClient for the given application Id. * The CloudClient is designed to be used by single application bundles. * CloudClient instances are acquired from the CloudService and they are released * when the work is completed. Generally, a CloudClient is acquired during the * activation phase of a bundle and it is released through the * {@link CloudClient#release} method during the bundle deactivation phase. *
* CloudClient will clean-up the subscriptions and the callback registrations * when the {@link CloudClient#release} method is called. *
* If the bundle using the CloudClient relies on subscriptions, * it is responsibility of the application to implement the * {@link CloudClientListener#onConnectionEstablished()} callback method * in the CloudCallbackHandler to restore the subscriptions it needs. * * @param appId * A String object specifying a unique application ID. * @return CloudClient instance * @throws KuraException */ public CloudClient newCloudClient(String appId) throws KuraException; /** * Returns the application identifiers for which a CloudClient instance was created. * * @return An array of application identifiers */ public String[] getCloudApplicationIdentifiers(); /** * Returns true if the underlying {@link org.eclipse.kura.data.DataService} is currently connected to the remote * server. * * @return */ public boolean isConnected(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/Cloudlet.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import java.util.Date; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraRequestPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentException; /** * Cloudlet is an abstract class that can be extended by services that wants to implement remote resource management. * The Cloudlet abstracts the detailed of the communication with the remote clients providing easy to use template * methods to be implemented by subclasses to handle CRUD operations on local resources. *
    *
  • {@link Cloudlet#doGet} is used to implement a READ request for a resource identified by the supplied * {@link CloudletTopic#getResources()} *
  • {@link Cloudlet#doPut} is used to implement a CREATE or UPDATE request for a resource identified by the supplied * {@link CloudletTopic#getResources()} *
  • {@link Cloudlet#doDel} is used to implement a DELETE request for a resource identified by the supplied * {@link CloudletTopic#getResources()} *
  • {@link Cloudlet#doPost} is used to implement other operations on a resource identified by the supplied * {@link CloudletTopic#getResources()} *
  • {@link Cloudlet#doExec} is used to perform applicatioon operation not necessary tied to a given resource. *
* * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.request.RequestHandler} */ @ConsumerType @Deprecated public abstract class Cloudlet implements CloudClientListener { private static final Logger logger = LogManager.getLogger(Cloudlet.class); protected static final int DFLT_PUB_QOS = 0; protected static final boolean DFLT_RETAIN = false; protected static final int DFLT_PRIORITY = 1; private static final int NUM_CONCURRENT_CALLBACKS = 2; private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS); private CloudService cloudService; private CloudClient cloudClient; private ComponentContext ctx; private final String applicationId; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setCloudService(CloudService cloudService) { this.cloudService = cloudService; } public void unsetCloudService(CloudService cloudService) { this.cloudService = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { // get the mqtt client for this application try { logger.info("Getting CloudApplicationClient for {}...", this.applicationId); this.cloudClient = this.cloudService.newCloudClient(this.applicationId); this.cloudClient.addCloudClientListener(this); // Don't subscribe because these are handled by the default subscriptions and we don't want to get messages // twice this.ctx = componentContext; } catch (KuraException e) { logger.error("Cannot activate", e); throw new ComponentException(e); } } protected void deactivate(ComponentContext componentContext) { // close the application client. // this will unsubscribe all open subscriptions logger.info("Releasing CloudApplicationClient for {}...", this.applicationId); if (this.cloudClient != null) { this.cloudClient.release(); } } protected Cloudlet(String appId) { this.applicationId = appId; } public String getAppId() { return this.applicationId; } protected CloudService getCloudService() { return this.cloudService; } protected CloudClient getCloudApplicationClient() { return this.cloudClient; } protected ComponentContext getComponentContext() { return this.ctx; } // ---------------------------------------------------------------- // // Default handlers // // ---------------------------------------------------------------- protected void doGet(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload) throws KuraException { logger.info("Default GET handler"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } protected void doPut(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload) throws KuraException { logger.info("Default PUT handler"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } protected void doPost(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload) throws KuraException { logger.info("Default POST handler"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } protected void doDel(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload) throws KuraException { logger.info("Default DEL handler"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } protected void doExec(CloudletTopic reqTopic, KuraRequestPayload reqPayload, KuraResponsePayload respPayload) throws KuraException { logger.info("Default EXEC handler"); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } @Override public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) { try { logger.debug("Control Arrived on topic: {}", appTopic); StringBuilder sb = new StringBuilder(this.applicationId).append("/").append("REPLY"); if (appTopic.startsWith(sb.toString())) { // Ignore replies return; } // Handle the message asynchronously to not block the master client callbackExecutor.submit(new MessageHandlerCallable(this, deviceId, appTopic, msg, qos, retain)); } catch (Throwable t) { logger.error("Unexpected throwable: {}", t); } } @Override public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) { logger.error("Unexpected message arrived on topic: " + appTopic); } @Override public void onConnectionLost() { logger.warn("Cloud Client Connection Lost!"); } @Override public void onConnectionEstablished() { logger.info("Cloud Client Connection Restored"); } @Override public void onMessageConfirmed(int messageId, String topic) { logger.debug("Message Confirmed (" + messageId + ")"); } @Override public void onMessagePublished(int messageId, String topic) { logger.debug("Message Published (" + messageId + ")"); } } class MessageHandlerCallable implements Callable { private static final Logger logger = LogManager.getLogger(MessageHandlerCallable.class); private final Cloudlet cloudApp; @SuppressWarnings("unused") private final String deviceId; private final String appTopic; private final KuraPayload msg; @SuppressWarnings("unused") private final int qos; @SuppressWarnings("unused") private final boolean retain; public MessageHandlerCallable(Cloudlet cloudApp, String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) { super(); this.cloudApp = cloudApp; this.deviceId = deviceId; this.appTopic = appTopic; this.msg = msg; this.qos = qos; this.retain = retain; } @Override public Void call() throws Exception { logger.debug("Control Arrived on topic: {}", this.appTopic); // Prepare the default response KuraRequestPayload reqPayload = KuraRequestPayload.buildFromKuraPayload(this.msg); KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { CloudletTopic reqTopic = CloudletTopic.parseAppTopic(this.appTopic); CloudletTopic.Method method = reqTopic.getMethod(); switch (method) { case GET: logger.debug("Handling GET request topic: {}", this.appTopic); this.cloudApp.doGet(reqTopic, reqPayload, respPayload); break; case PUT: logger.debug("Handling PUT request topic: {}", this.appTopic); this.cloudApp.doPut(reqTopic, reqPayload, respPayload); break; case POST: logger.debug("Handling POST request topic: {}", this.appTopic); this.cloudApp.doPost(reqTopic, reqPayload, respPayload); break; case DEL: logger.debug("Handling DEL request topic: {}", this.appTopic); this.cloudApp.doDel(reqTopic, reqPayload, respPayload); break; case EXEC: logger.debug("Handling EXEC request topic: {}", this.appTopic); this.cloudApp.doExec(reqTopic, reqPayload, respPayload); break; default: logger.error("Bad request topic: {}", this.appTopic); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_BAD_REQUEST); break; } } catch (IllegalArgumentException e) { logger.error("Bad request topic: {}", this.appTopic); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_BAD_REQUEST); } catch (KuraException e) { logger.error("Error handling request topic: {}\n{}", this.appTopic, e); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR); respPayload.setException(e); } try { CloudClient cloudClient = this.cloudApp.getCloudApplicationClient(); respPayload.setTimestamp(new Date()); StringBuilder sb = new StringBuilder("REPLY").append("/").append(reqPayload.getRequestId()); String requesterClientId = reqPayload.getRequesterClientId(); logger.debug("Publishing response topic: {}", sb.toString()); cloudClient.controlPublish(requesterClientId, sb.toString(), respPayload, Cloudlet.DFLT_PUB_QOS, Cloudlet.DFLT_RETAIN, Cloudlet.DFLT_PRIORITY); } catch (KuraException e) { logger.error("Error publishing response for topic: {}\n{}", this.appTopic, e); } return null; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/CloudletTopic.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.message.KuraMessage} properties */ @ProviderType @Deprecated public class CloudletTopic { public enum Method { GET, PUT, POST, DEL, EXEC; } private Method method; private String[] resources; public static CloudletTopic parseAppTopic(String appTopic) { CloudletTopic edcApplicationTopic = new CloudletTopic(); String[] parts = appTopic.split("/"); edcApplicationTopic.method = Method.valueOf(parts[0]); if (parts.length > 1) { edcApplicationTopic.resources = new String[parts.length - 1]; for (int i = 0; i < edcApplicationTopic.resources.length; i++) { edcApplicationTopic.resources[i] = parts[i + 1]; } } return edcApplicationTopic; } private CloudletTopic() { super(); } public Method getMethod() { return this.method; } public String[] getResources() { return this.resources; } @Override public String toString() { StringBuilder sb = new StringBuilder(this.method.name()); if (this.resources != null) { for (String resource : this.resources) { sb.append("/"); sb.append(resource); } } return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/factory/CloudServiceFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloud.factory; import java.util.List; import java.util.Set; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * A CloudServiceFactory represents an OSGi Declarative Service Component * which registers {@link org.eclipse.kura.cloud.CloudService}S in the framework. * The Component creates multiple component instances upon reception of a configuration * created through the Configuration Service. *
* It provides a CloudService implementation that can be used to connect to a specific Cloud platform. *
* Typically, each CloudService created by a CloudServiceFactory * establishes and manages its own connection, for example an Mqtt connection. *
* Multiple CloudServiceFactory services can be registered in the framework to support multiple simultaneous * connections to different Cloud platforms. *
* Kura provides a default CloudServiceFactory implementation and creates a default CloudService. *
* A CloudServiceFactory manages the construction of a CloudService and the services it depends on. * While the same can be achieved through the {@link org.eclipse.kura.configuration.ConfigurationService}, * CloudServiceFactory simplifies this process and offers more control. *
* For example, in a stack architecture with CloudService at the top of the stack * and where lower layers are also components, * an implementation of CloudServiceFactory could create new configurations * for all the stack layers thus constructing a new whole stack instance. *
* The Kura {@link org.eclipse.kura.cloud.CloudService}/{@link org.eclipse.kura.data.DataService}/{@link org.eclipse.kura.data.DataTransportService} * cloud stack represents an example of the above architecture * and can serve as a reference implementation for alternative Cloud stacks. *
* In order to leverage the Kura configuration persistence in snapshot files, * an implementation will use the {@link org.eclipse.kura.configuration.ConfigurationService} * to create component configurations. * * @since 1.0.8 * * @noimplement This interface is not intended to be implemented by clients. * * @deprecated Please consider using {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory} */ @ProviderType @Deprecated public interface CloudServiceFactory { /** * The name of the property set in a @{link org.eclipse.kura.cloud.CloudService} configuration created * through {@link #createConfiguration}. * The property is set in the cloud service instance to relate it with the Factory that generated the whole cloud * stack. * * @since 1.1.0 */ public static final String KURA_CLOUD_SERVICE_FACTORY_PID = "kura.cloud.service.factory.pid"; /** * Returns the factory PID of the OSGi Factory Component represented by this CloudServiceFactory. * * @return a String representing the factory PID of the Factory Component. */ String getFactoryPid(); /** * Creates a {@link org.eclipse.kura.cloud.CloudService} instance and initializes its configuration with the defaults * expressed in the Metatype of the target component factory providing the CloudService. *
* Implementation will normally rely on {@link org.eclipse.kura.configuration.ConfigurationService#createFactoryConfiguration} * to perform the actual creation of the component instance and the persistence of the component configuration. *
* The created CloudService instance will have its kura.service.pid property * set to the value provided in the pid parameter. *
* Kura apps can look up the created CloudService instance through {@link org.osgi.service.component.ComponentContext#locateServices} * by filtering on the kura.service.pid property. *
* Likely, Kura apps will rely on OSGi Declarative Services to have their CloudService dependencies satisfied based * on a target filter on the value of the property kura.service.pid * in their component definition. *
* In the following example a Kura app declares two dependencies on CloudServiceS whose PIDs are * myCloudService and anotherCloudService: * *
     * <reference name="myCloudServiceReference"
     *              policy="static"
     *              bind="setMyCloudService"
     *              unbind="unsetMyCloudService"
     *              cardinality="1..1"
     *              interface="org.eclipse.kura.cloud.CloudService"/>
     * <property  name="myCloudServiceReference.target"
     *              type="String"
     *              value="(kura.service.pid=myCloudService)"/>
     *
     * <reference name="anotherCloudServiceReference"
     *              policy="static"
     *              bind="setAnotherCloudService"
     *              unbind="unsetAnotherCloudService"
     *              cardinality="1..1"
     *              interface="org.eclipse.kura.cloud.CloudService"/>
     * <property  name="anotherCloudServiceReference.target"
     *              type="String"
     *              value="(kura.service.pid=anotherCloudService)"/>
     * 
* * @param pid * the Kura persistent identifier, kura.service.pid, of the factory component configuration. * @throws KuraException */ void createConfiguration(String pid) throws KuraException; /** * Returns the list of kura.service.pids that compose the cloud stack associated with the provided * kura.service.pid of the factory component configuration. * * @param pid * the Kura persistent identifier, kura.service.pid, of the factory component configuration. * @return List<String>, the list of kura.service.pids associated with the specified factory component * configuration. * @throws KuraException * if the specified kura.service.pid is not correct or compliant with what the factory * implementation expects * @since 1.1.0 */ List getStackComponentsPids(String pid) throws KuraException; /** * Deletes a previously created configuration deactivating the associated {@link org.eclipse.kura.cloud.CloudService} instance. * * @param pid * the Kura persistent identifier, kura.service.pid, of the factory component configuration. * @throws KuraException */ void deleteConfiguration(String pid) throws KuraException; /** * Return a set of services managed by this factory *
* It is up to the factory how it does assembles this. The PIDs returned by this list must be the PIDs assigned * to the OSGi service property kura.service.pid and it must be possible to pass all those results into * the method {@link #getStackComponentsPids(String)} of the same factory instance. *
* The IDs returned by this method must not necessarily point to registered OSGi services. But if they do, they must * point only to instances of the {@link org.eclipse.kura.cloud.CloudService}. * * @return the set of services, never returns {@code null} * @throws KuraException * * @since 1.1.0 */ Set getManagedCloudServicePids() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/factory/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Contains interfaces to manage the construction of Cloud Services. */ @Deprecated package org.eclipse.kura.cloud.factory; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloud/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides services for managing communications between M2M applications and remote servers. Types of communications * include simple publish/subscribe models to more complex * request/response and remote resource management. * */ package org.eclipse.kura.cloud; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudConnectionConstants.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection; /** * Provides constants that are used by cloud connections to relate service instances to their respective * {@link CloudEndpoint} or {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory}. * * @since 2.0 */ public enum CloudConnectionConstants { /** * The key of the property that specifies the {@code kura.service.pid} of the associated * {@link CloudEndpoint} in {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} * or {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} component configuration. */ CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME("cloud.endpoint.service.pid"), /** * The key of the property that specifies the {@code kura.service.pid} of the associated * {@link org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory} in {@link CloudEndpoint} component definition. */ CLOUD_CONNECTION_FACTORY_PID_PROP_NAME("cloud.connection.factory.pid"); private String value; private CloudConnectionConstants(final String value) { this.value = value; } public String value() { return this.value; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudConnectionManager.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraDisconnectException; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.osgi.annotation.versioning.ProviderType; /** * A {@link CloudEndpoint} can implement CloudConnectionManager to support the management of * long-lived/always on connections. * * This interface provides methods to connect, disconnect and get the connection state of the associated CloudEndpoint. * It also provides methods to register {@link CloudConnectionListener}s that will be notified of connection-related * events. * * The implementor must register itself as a CloudConnectionManager OSGi service provider. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.0 */ @ProviderType public interface CloudConnectionManager { /** * Establishes a connection to the configured cloud platform. * * @throws org.eclipse.kura.KuraException * if the operation fails */ public void connect() throws KuraConnectException; /** * Performs a clean disconnection from the cloud platform. * * @throws org.eclipse.kura.KuraException * if the operation fails */ public void disconnect() throws KuraDisconnectException; /** * Tests if the connection is alive. * * @return {@code true} if the framework is connected to the remote server. {@code false} otherwise. */ public boolean isConnected(); /** * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified. * * @param cloudConnectionListener * a {@link CloudConnectionListener} instance */ public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener); /** * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events * notifications. * * @param cloudConnectionListener */ public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/CloudEndpoint.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection; import java.util.Collections; import java.util.Map; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.osgi.annotation.versioning.ProviderType; /** * CloudEndpoint provide APIs to ease the communication with a cloud platform allowing to publish a message, manage * subscribers, subscribe to message delivery notification or get information about the specific cloud endpoint * configuration. * * Each CloudEndpoint is referenced by zero or more {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} * and {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} instances. * * Applications should not use directly this API but, instead, use the * {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} and the * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} interfaces to give applications the capabilities * to publish and receive messages. * * The implementor must register itself as a CloudEndpoint OSGi service provider. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.0 */ @ProviderType public interface CloudEndpoint { /** * Publishes the received {@link KuraMessage} to the associated cloud platform and returns, if supported, a String * representing a message ID. * {@code null} is returned if the cloud endpoint will not confirm the message delivery, either because this is not * supported by the underlying protocol or because the cloud endpoint itself is not implemented or configured to * request the confirmation. * * @param message * the {@link KuraMessage} to be published * @return a String representing the message ID or {@code null} if not supported * @throws KuraException * if the publishing operation fails. */ public String publish(KuraMessage message) throws KuraException; /** * Registers the provided {@link CloudSubscriberListener} using the specified {@code subscriptionProperties} that * will allow * to disambiguate the specific subscriptions. * * @param subscriptionProperties * a map representing the subscription context * @param cloudSubscriberListener * a {@link CloudSubscriberListener} object that will be notified when a message is received in a context * that matches the one identified by the subscription properties. */ public void registerSubscriber(Map subscriptionProperties, CloudSubscriberListener cloudSubscriberListener); /** * Unregisters the provided {@code cloudSubscriberListener}. * * @param cloudSubscriberListener * the {@link CloudSubscriberListener} to be unregistered. */ public void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener); /** * Provides information related to the associated connection. The information provided depends on the specific * implementation and type of connection to the remote resource. The default implementation returns an empty * map. * * @return a map that represents all the information related to the specific connection. */ public default Map getInfo() { return Collections.emptyMap(); } /** * The implementation will register the {@link CloudDeliveryListener} instance passed as argument. Once a cloud * connection related event happens, all the registered {@link CloudDeliveryListener}s will be notified. * * @param cloudDeliveryListener * a {@link CloudDeliveryListener} instance */ public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener); /** * Unregisters the provided {@link CloudDeliveryListener} instance from cloud connection related events * notifications. * * @param cloudConnectionListener */ public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/factory/CloudConnectionFactory.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.factory; import java.util.List; import java.util.Set; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * A {@link CloudConnectionFactory} is responsible to register {@link org.eclipse.kura.cloudconnection.CloudEndpoint} * instances in the framework. * The Component creates multiple component instances upon reception of a configuration * created through the Configuration Service. * * It provides all the implementations that can be used to connect to a specific Cloud platform. * * A {@link CloudConnectionFactory} must create a {@link org.eclipse.kura.cloudconnection.CloudEndpoint} and, * eventually, a {@link org.eclipse.kura.cloudconnection.CloudConnectionManager} that are used to establish and manage * the connection to a cloud platform, for example an Mqtt connection. * * Multiple {@link CloudConnectionFactory} services can be registered in the framework to support multiple simultaneous * connections to different Cloud platforms. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.0 */ @ProviderType public interface CloudConnectionFactory { /** * The name of the property set in the instance configuration created * through {@link #createConfiguration}. * The property is set in the instance to relate it with the Factory that generated * the whole cloud stack. */ public static final String KURA_CLOUD_CONNECTION_FACTORY_PID = "kura.cloud.connection.factory.pid"; /** * Returns the factory PID of the OSGi Factory Component represented by this {@link CloudConnectionFactory}. * * @return a String representing the factory PID of the Factory Component. */ public String getFactoryPid(); /** * This method creates a CloudEndpoint instance and, eventually, more service instances that are necessary to * identify and the manage the endpoint and the connection. It initializes the configuration of the created services * with the defaults expressed in the Metatype of the target component factories. * * The created Cloud Endpoint instance will have its {@code kura.service.pid} property * set to the value provided in the {@code pid} parameter. * * @param pid * the Kura persistent identifier ({@code kura.service.pid}) of the Cloud Endpoint service * instance created by this factory. * @throws KuraException * an exception is thrown in case the creation operation fails */ public void createConfiguration(String pid) throws KuraException; /** * Returns the list of {@code kura.service.pid}s that compose the cloud connection associated with the provided * {@code kura.service.pid}. * * @param pid * the Kura persistent identifier, {@code kura.service.pid} * @return the {@link List} of {@code kura.service.pid}s related to the provided {@code pid}. * @throws KuraException * if the specified {@code kura.service.pid} is incorrect. */ public List getStackComponentsPids(String pid) throws KuraException; /** * Deletes a previously created configuration deactivating the associated instances. * * @param pid * the Kura persistent identifier, {@code kura.service.pid} of a Cloud Endpoint * @throws KuraException * if the provided {@code kura.service.pid} is incorrect or the delete operation fails. */ public void deleteConfiguration(String pid) throws KuraException; /** * Returns a set of {@code kura.service.pid} that corresponds to the Cloud Endpoint services managed by this * factory. * * @return the set of services or an empty set. * @throws KuraException */ public Set getManagedCloudConnectionPids() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/factory/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Contains interfaces to manage the construction of Cloud Connection Services. */ package org.eclipse.kura.cloudconnection.factory; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/CloudConnectionListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.listener; import org.osgi.annotation.versioning.ConsumerType; /** * The CloudConnectionListener interface is implemented by applications that want to be notified on connection * status changes. * To be notified, the implementor needs to register itself to a specific {@link org.eclipse.kura.cloudconnection.CloudConnectionManager}. * * @since 2.0 */ @ConsumerType public interface CloudConnectionListener { /** * Notifies a clean disconnection from the cloud platform. */ public void onDisconnected(); /** * Called when the client has lost its connection to the cloud platform. This is only a notification, the callback * handler * should not attempt to handle the reconnect. * * If the bundle using the client relies on subscriptions beyond the default ones, * it is responsibility of the application to implement the {@link CloudConnectionListener#onConnectionEstablished} * callback method to restore the subscriptions it needs after a connection loss. */ public void onConnectionLost(); /** * Called when the cloud stack has successfully connected to the cloud platform. * * If the bundle using the client relies on subscriptions beyond the default ones, * it is responsibility of the application to implement the {@link CloudConnectionListener#onConnectionEstablished} * callback method to restore the subscriptions it needs after a connection loss. */ public void onConnectionEstablished(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/CloudDeliveryListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.listener; import org.osgi.annotation.versioning.ConsumerType; /** * Implementors of this interface will be able to handle cloud stack related * events that deal with message delivery. * * All the registered listeners are called synchronously at the occurrence of the event. * It is expected that implementors of this interface do NOT perform long running tasks in the implementation of this * interface. * * @since 2.0 */ @ConsumerType public interface CloudDeliveryListener { /** * Confirms message delivery to the cloud platform. * * @param messageId */ public void onMessageConfirmed(String messageId); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs to listen to cloud connection notifications, such as connection status changes and message delivery * confirmations. * */ package org.eclipse.kura.cloudconnection.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/message/KuraMessage.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.message; import java.util.HashMap; import java.util.Map; import org.eclipse.kura.message.KuraPayload; import org.osgi.annotation.versioning.ProviderType; /** * The class KuraMessage represents a message that is shared between an application running in the framework and, for * example, a {@link org.eclipse.kura.cloudconnection.publisher.CloudPublisher} or * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber}. * It is composed by a {@link KuraPayload} and properties that enrich the context of the message. * The content of the {@code properties} field is not fixed or mandatory and represent message-related options. * Depending on the application, the value in the {@code properties} field can be used or not. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.0 */ @ProviderType public class KuraMessage { private final Map properties; private final KuraPayload payload; public KuraMessage(KuraPayload payload) { this.properties = new HashMap<>(); this.payload = payload; } public KuraMessage(KuraPayload payload, Map properties) { this.properties = new HashMap<>(properties); this.payload = payload; } public Map getProperties() { return this.properties; } public KuraPayload getPayload() { return this.payload; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/message/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Defines the recommended structure for the messages produced by an application that need to be sent to a remote cloud * platform. */ package org.eclipse.kura.cloudconnection.message; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides services for managing connections between the IoT framework and the remote servers. * The term Cloud Connection identifies a set of interfaces that allow to specify and manage the cloud endpoint * specified. * Using the provided interfaces, the user application is able to publish messages to the cloud platform without knowing * the low level specificities of the underneath protocols used to communicate with the cloud platform. Interfaces are * available also to register subscribers that will receive and process messages from the cloud platform to the end * device. * */ package org.eclipse.kura.cloudconnection; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/CloudNotificationPublisher.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.publisher; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface used to identify a Cloud Publisher dedicated to send notifications until completion of a long-lived * operation initially handled by a {@link org.eclipse.kura.cloudconnection.request.RequestHandler}. * * @since 2.0 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudNotificationPublisher extends CloudPublisher { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/CloudPublisher.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.publisher; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.osgi.annotation.versioning.ProviderType; /** * The CloudPublisher interface is an abstraction on top of the {@link org.eclipse.kura.cloudconnection.CloudEndpoint} * to simplify the publishing process for each application running in the framework. * A CloudPublisher is used to publish the specified {@link KuraMessage} to a cloud platform. * The CloudPublisher and the associated CloudEndpoint implementations abstract, to the user applications, all the low * level specificities like the message destination address, quality of service or properties because those are added by * the {@link CloudPublisher} implementation based, for example, on a configuration. * * When an application wants to publish, it has to take a CloudPublisher instance and use the * {@link CloudPublisher#publish(KuraMessage)} method, passing as argument a KuraMessage. * * Every KuraMessage accepted by the CloudPublisher is associated to a string identifier that can be * used to confirm that the KuraMessage has been published. * However, the semantics of the confirmation depends on both the implementation and the configuration of the * connection. * For example, if the protocol of the cloud connection supports message identifiers and acknowledgments, the * implementation will map the message identifier to the KuraMessage identifier and confirm it when * the message identifier is acknowledged. If the protocol does not support message identifiers, or the message does not * request an acknowledge, a confirmed KuraMessage identifier may at most indicate that the message has been * successfully transmitted. There is no guarantee that a KuraMessage identifier will ever be confirmed. It is * important that the implementation of the CloudPublisher and its configuration match the assumptions of the * API consumer about the delivery. * * For example, if the correct behavior of an application requires guaranteed message delivery, the * application should be configured to use a reliable publisher. Of course, applications that do not require this will * work with any publisher. * * @since 2.0 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudPublisher { /** * Publishes the received {@link KuraMessage} using the associated cloud connection. * * @param message * The {@link KuraMessage} to be published * @return a String representing the message ID. {@code null} is returned if the cloud endpoint will not confirm the * message delivery, either because this is not supported by the underlying protocol or because the cloud * endpoint itself is not implemented or configured to request the confirmation. The message ID can be * confirmed when the message is delivered. See {@link CloudDeliveryListener}. * @throws KuraException * if the publishing operation fails. */ public String publish(KuraMessage message) throws KuraException; /** * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified. * * @param cloudConnectionListener * a {@link CloudConnectionListener} instance */ public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener); /** * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events * notifications. * * @param cloudConnectionListener */ public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener); /** * The implementation will register the {@link CloudDeliveryListener} instance passed as argument. Once a cloud * connection related event happens, all the registered {@link CloudDeliveryListener}s will be notified. * * @param cloudDeliveryListener * a {@link CloudDeliveryListener} instance */ public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener); /** * Unregisters the provided {@link CloudDeliveryListener} instance from cloud connection related events * notifications. * * @param cloudConnectionListener */ public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/publisher/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides services for managing communications between local applications and remote servers. * */ package org.eclipse.kura.cloudconnection.publisher; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandler.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.request; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.osgi.annotation.versioning.ConsumerType; /** * Implemented by services that want to implement remote resource management. * *
    *
  • {@link RequestHandler#doGet} is used to implement a READ request for a resource identified in the supplied * {@link KuraMessage)}
  • *
  • {@link RequestHandler#doPut} is used to implement a CREATE or UPDATE request for a resource identified in the * supplied {@link KuraMessage}
  • *
  • {@link RequestHandler#doDel} is used to implement a DELETE request for a resource identified in the supplied * {@link KuraMessage}
  • *
  • {@link RequestHandler#doPost} is used to implement other operations on a resource identified in the supplied * {@link KuraMessage}
  • *
  • {@link RequestHandler#doExec} is used to perform application operation not necessary tied to a given * resource.
  • *
* * Every request is also associated to a {@link RequestHandlerContext} that specifies the request context and can be * used to send notification messages, keeping the link with the original cloud stack that started the interaction. * * @since 2.0 * @noimplement This interface is not intended to be implemented by clients. */ @ConsumerType public interface RequestHandler { /** * Used to implement a READ request for a resource identified by the supplied {@link CloudletResources)} * * @param context * a request context that can be used, for example, to publish notification messages to the remote cloud * platform * @param reqMessage * represents, as a {@link KuraMessage}, the received message * @return the response to be provided back as {@link KuraMessage} * @throws KuraException * An exception is thrown in every condition where the request cannot be full fitted due to wrong * request parameters or exceptions during processing */ public default KuraMessage doGet(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "get"); } /** * Used to implement a CREATE or UPDATE request for a resource identified by the supplied {@link CloudletResources)} * * @param context * a request context that can be used, for example, to publish notification messages to the remote cloud * platform * @param reqMessage * represents as a {@link KuraMessage} the received message * @return the response to be provided back as {@link KuraMessage} * @throws KuraException * An exception is thrown in every condition where the request cannot be full fitted due to wrong * request parameters or exceptions during processing */ public default KuraMessage doPut(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "put"); } /** * Used to implement other operations on a resource identified by the supplied {@link CloudletResources)} * * @param context * a request context that can be used, for example, to publish notification messages to the remote cloud * platform * @param reqMessage * represents as a {@link KuraMessage} the received message * @return the response to be provided back as {@link KuraMessage} * @throws KuraException * An exception is thrown in every condition where the request cannot be full fitted due to wrong * request parameters or exceptions during processing */ public default KuraMessage doPost(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "post"); } /** * Used to implement a DELETE request for a resource identified by the supplied {@link CloudletResources)} * * @param context * a request context that can be used, for example, to publish notification messages to the remote cloud * platform * @param reqMessage * represents as a {@link KuraMessage} the received message * @return the response to be provided back as {@link KuraMessage} * @throws KuraException * An exception is thrown in every condition where the request cannot be full fitted due to wrong * request parameters or exceptions during processing */ public default KuraMessage doDel(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "delete"); } /** * Used to perform application operation not necessary tied to a given resource * * @param context * a request context that can be used, for example, to publish notification messages to the remote cloud * platform * @param reqMessage * represents as a {@link KuraMessage} the received message * @return the response to be provided back as {@link KuraMessage} * @throws KuraException * An exception is thrown in every condition where the request cannot be full fitted due to wrong * request parameters or exceptions during processing */ public default KuraMessage doExec(RequestHandlerContext context, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "exec"); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerContext.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.request; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.osgi.annotation.versioning.ProviderType; /** * PoJo class used to wrap the context associated to a request received from the cloud and passed to a * {@link RequestHandler}. * It should be used, for example, to provide the context that will be leveraged by a {@link RequestHandler} to publish * event notifications to a remote cloud platform. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public class RequestHandlerContext { private final CloudNotificationPublisher notificationPublisher; private final Map contextProperties; public RequestHandlerContext(CloudNotificationPublisher notificationPublisher, Map contextProperties) { this.notificationPublisher = notificationPublisher; this.contextProperties = new HashMap<>(contextProperties); } public CloudNotificationPublisher getNotificationPublisher() { return this.notificationPublisher; } public Map getContextProperties() { return Collections.unmodifiableMap(this.contextProperties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerContextConstants.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.request; /** * This class is an enumeration that wraps property keys used to defined a Context for a RequestHandler. * * @since 2.0 */ public enum RequestHandlerContextConstants { TENANT_ID, DEVICE_ID, NOTIFICATION_PUBLISHER_PID; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerMessageConstants.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.request; /** * This class is an enumeration that wraps some of the possible property keys set in the properties of a * {@link org.eclipse.kura.cloudconnection.message.KuraMessage} used for request/response. * * @since 2.0 */ public enum RequestHandlerMessageConstants { /** * Request arguments. The corresponding value must be a {@code List}. */ ARGS_KEY("args"); private String value; RequestHandlerMessageConstants(final String value) { this.value = value; } public String value() { return this.value; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/RequestHandlerRegistry.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.request; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Interface used to register or unregister {@link RequestHandler}s identified by a specific id. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public interface RequestHandlerRegistry { /** * Registers a {@link RequestHandler} identified by the specified {@code id}. Once registered, the * {@link RequestHandler} instance can be notified for request messages targeting the registered {@code id} * * @param id * a String identifying a specific {@link RequestHandler} * @param requestHandler * a {@link RequestHandler} instance identified by the specified {@code id} * @throws KuraException */ public void registerRequestHandler(String id, RequestHandler requestHandler) throws KuraException; /** * Unregisters the {@link RequestHandler} identified by the specified {@code id}. From that moment on, no * notifications will be sent to the unregistered {@RequestHandler} * * @param id * a String identifying a specific {@link RequestHandler} * @throws KuraException */ public void unregister(String id) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/request/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides services for managing requests and response between the gateway and the remote cloud platform. * */ package org.eclipse.kura.cloudconnection.request; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/CloudSubscriber.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.subscriber; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.osgi.annotation.versioning.ProviderType; /** * Interface intended to have a specific implementation associated to a * {@link org.eclipse.kura.cloudconnection.CloudEndpoint} that wraps the * specificities related to the targeted cloud provider. * * The {@link CloudSubscriber} interface is an abstraction on top of the * {@link org.eclipse.kura.cloudconnection.CloudEndpoint} to simplify the * subscription and notification process, for each application running in the framework. * * When an application wants to receive a message from the cloud, it has to take a {@link CloudSubscriber} instance and * register itself as a {@link CloudSubscriberListener}, in order to be notified when a message is received from the * associated cloud stack. * * In most cases, the consumers are not interested in the header of the received message and assume to always receive * the * same kind of message. In order to receive different kinds of messages, the consumer should register to multiple * subscribers. * * Some messaging protocols have a hierarchical addressing structure supporting multilevel wildcard subscriptions. For * example, an MQTT address (topic) hierarchy might look like * building/${building-number}/apartment/${apartment-number}/heating/temperature. * To receive the heating temperature measurements for all the buildings and apartments the subscriber can be configured * to subscribe to building/+/apartment/+/heating/temperature. When a message is received, the subscriber will notify * the application providing the payload received and some properties that are implementation specific, depending on the * subscriber, and that can allow the application to understand the corresponding resource. * * @since 2.0 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudSubscriber { /** * Registers the {@link CloudSubscriberListener} instance passed as an argument. All the registered * {@link CloudSubscriberListener}s will be notified by the implementation when a message is received. * * @param listener * a {@link CloudSubscriberListener} instance that will be notified when a message will be received from * the remote cloud platform. */ public void registerCloudSubscriberListener(CloudSubscriberListener listener); /** * Unregisters the provided {@link CloudSubscriberListener} from the list of the notified listeners. * * @param listener */ public void unregisterCloudSubscriberListener(CloudSubscriberListener listener); /** * The implementation will register the {@link CloudConnectionListener} instance passed as argument. Once a cloud * connection related event happens, all the registered {@link CloudConnectionListener}s will be notified. * * @param cloudConnectionListener * a {@link CloudConnectionListener} instance */ public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener); /** * Unregisters the provided {@link CloudConnectionListener} instance from cloud connection related events * notifications. * * @param cloudConnectionListener */ public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/listener/CloudSubscriberListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.cloudconnection.subscriber.listener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.osgi.annotation.versioning.ConsumerType; /** * The {@link CloudSubscriberListener} interface has to be implemented by applications that needs to be notified of * events in the subscriber. * Notification methods are invoked whenever a message is received in the associated * {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber}. * * @since 2.0 */ @ConsumerType @FunctionalInterface public interface CloudSubscriberListener { /** * Called by the {@link org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber} when a message is received from * the remote cloud platform. * The received message will be parsed and passed as a {@link KuraMessage} to the listener. * * @param message * The {@link KuraMessage} that wraps the received message. */ public void onMessageArrived(KuraMessage message); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides apis that allow to register subscriber applications. * */ package org.eclipse.kura.cloudconnection.subscriber.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/cloudconnection/subscriber/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides services for subscribing to remote servers and allows to invoke local applications. * */ package org.eclipse.kura.cloudconnection.subscriber; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/CommConnection.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.comm; import java.io.IOException; import javax.microedition.io.StreamConnection; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This is the primary control class for a Serial port. An instance of * this class may be operated on by more than one thread. Settings will be * those of the last thread to successfully change each particular setting. *

* Code written to use a javax.comm.SerialPort object in a shared mode should * make use of synchronization blocks where exclusive transactions are wanted. * In most instances, both the OutputStream and the InputStream should be * synchronized on, normally with the OutputStream being synchronized first. * *

 * Example Code:
 *         try {
 *            String uri = new CommURI.Builder("/dev/tty.PL2303-00001004")
 *                                        .withBaudRate(19200)
 *                                        .withDataBits(8)
 *                                        .withStopBits(1)
 *                                        .withParity(0)
 *                                        .withTimeout(2000)
 *                                        .build().toString();
 *            CommConnection connOne = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);
 *            assertNotNull(connOne);
 *            uri = new CommURI.Builder("/dev/tty.PL2303-00002006")
 *                                        .withBaudRate(19200)
 *                                        .withDataBits(8)
 *                                        .withStopBits(1)
 *                                        .withParity(0)
 *                                        .withTimeout(2000)
 *                                        .build().toString();
 *            CommConnection connTwo = (CommConnection) CommTest.connectionFactory.createConnection(uri, 1, false);
 *            assertNotNull(connTwo);
 *
 *            InputStream isOne = connOne.openInputStream();
 *            OutputStream osOne = connOne.openOutputStream();
 *            InputStream isTwo = connTwo.openInputStream();
 *            OutputStream osTwo = connTwo.openOutputStream();
 *
 *            assertNotNull(isOne);
 *            assertNotNull(osOne);
 *            assertNotNull(isTwo);
 *            assertNotNull(osTwo);
 *
 *            //write from one to two
 *            byte[] array = "this is a message from one to two\n".getBytes();
 *            osOne.write(array);
 *            StringBuffer sb = new StringBuffer();
 *            int c;
 *            while((c = isTwo.read()) != 0xa) {
 *                sb.append((char)c);
 *            }
 *            System.out.println("Port 2: Read from serial port two: " + sb.toString());
 *
 *            array = "this is a message from two to one\n".getBytes();
 *            osTwo.write(array);
 *            sb = new StringBuffer();
 *            while((c = isOne.read()) != 0xa) {
 *                sb.append((char)c);
 *            }
 *            System.out.println("Port 1: Read from serial port: " + sb.toString());
 *
 *            isOne.close();
 *            osOne.close();
 *            isOne = null;
 *             osOne = null;
 *            isTwo.close();
 *            osTwo.close();
 *            isTwo = null;
 *            osTwo = null;
 *            connOne.close();
 *            connOne = null;
 *            connTwo.close();
 *            connTwo = null;
 *        } catch (Exception e) {
 *            e.printStackTrace();
 *        }
 * 
* * Note: avoid blocking read (InputStream.read()) if the InputStream can be closed on a different thread, * in this case, the read will never exit and the thread will be blocked forever. * * It is preferable to test InputStream.available before InputStream.read(): * *
 *        if (isOne.available() != 0) {
 *            c = isOne.read();
 *        } else {
 *        try {
 *            Thread.sleep(100);
 *            continue;
 *        } catch (InterruptedException e) {
 *            return;
 *        }
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CommConnection extends StreamConnection { /** * Returns the URI for this connection. * * @return this connection URI */ public CommURI getURI(); /** * Sends and array of bytes to a CommConnection * * @param message * the array of bytes to send to the CommConnection * @throws KuraException * @throws IOException */ public void sendMessage(byte[] message) throws KuraException, IOException; /** * Sends and array of bytes to a CommConnection and returns an array of bytes * that represents the 'response' to the command. If the timeout is exceeded * before any bytes are read on the InputStream null is returned. This is * meant to be used in common command/response type situations when communicating * with serial devices * * @param command * the array of bytes to send to the CommConnection * @param timeout * the maximum length of time to wait before returning a null * response in the event no response is ever returned. * @return an array of bytes representing the response * @throws KuraException * @throws IOException */ public byte[] sendCommand(byte[] command, int timeout) throws KuraException, IOException; public byte[] sendCommand(byte[] command, int timeout, int demark) throws KuraException, IOException; /** * Reads all bytes that are waiting in the serial port buffer and returns them in * an array. This can be used to read unsolicited messages from an attached * serial device. * * @return the array of bytes buffered on the InputStream if any * @throws KuraException * @throws IOException */ public byte[] flushSerialBuffer() throws KuraException, IOException; @Override public void close() throws IOException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/CommURI.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.comm; import java.net.URISyntaxException; import javax.comm.SerialPort; import org.osgi.annotation.versioning.ProviderType; /** * Represents a Uniform Resource Identifier (URI) for a Comm/Serial Port. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class CommURI { public static final int DATABITS_5 = SerialPort.DATABITS_5; public static final int DATABITS_6 = SerialPort.DATABITS_6; public static final int DATABITS_7 = SerialPort.DATABITS_7; public static final int DATABITS_8 = SerialPort.DATABITS_8; public static final int PARITY_EVEN = SerialPort.PARITY_EVEN; public static final int PARITY_MARK = SerialPort.PARITY_MARK; public static final int PARITY_NONE = SerialPort.PARITY_NONE; public static final int PARITY_ODD = SerialPort.PARITY_ODD; public static final int PARITY_SPACE = SerialPort.PARITY_SPACE; public static final int STOPBITS_1 = SerialPort.STOPBITS_1; public static final int STOPBITS_1_5 = SerialPort.STOPBITS_1_5; public static final int STOPBITS_2 = SerialPort.STOPBITS_2; public static final int FLOWCONTROL_NONE = SerialPort.FLOWCONTROL_NONE; public static final int FLOWCONTROL_RTSCTS_IN = SerialPort.FLOWCONTROL_RTSCTS_IN; public static final int FLOWCONTROL_RTSCTS_OUT = SerialPort.FLOWCONTROL_RTSCTS_OUT; public static final int FLOWCONTROL_XONXOFF_IN = SerialPort.FLOWCONTROL_XONXOFF_IN; public static final int FLOWCONTROL_XONXOFF_OUT = SerialPort.FLOWCONTROL_XONXOFF_OUT; private final String port; private final int baudRate; private final int dataBits; private final int stopBits; private final int parity; private final int flowControl; private final int openTimeout; private final int receiveTimeout; /** * Constructor to build the CommURI * * @param builder * the builder that contains the comm port parameters */ private CommURI(Builder builder) { this.port = builder.builderPort; this.baudRate = builder.builderBaudRate; this.dataBits = builder.builderDdataBits; this.stopBits = builder.builderStopBits; this.parity = builder.builderParity; this.flowControl = builder.builderFlowControl; this.openTimeout = builder.builderOpenTimeout; this.receiveTimeout = builder.builderReceiveTimeout; } /** * The COM port or device node associated with this port * * @return a {@link String } representing the port */ public String getPort() { return this.port; } /** * The baud rate associated with the port * * @return an int representing the baud rate */ public int getBaudRate() { return this.baudRate; } /** * The number of data bits associated with the port * * @return an int representing the number of data bits */ public int getDataBits() { return this.dataBits; } /** * The number of stop bits associated with the port * * @return an int representing the number of stop bits */ public int getStopBits() { return this.stopBits; } /** * The parity associated with the port * * @return an int representing the parity */ public int getParity() { return this.parity; } /** * The flow control associated with the port * * @return an int representing the flow control */ public int getFlowControl() { return this.flowControl; } /** * The open timeout associated with the port, this method is identical to {@link #getOpenTimeout()} * * @deprecated Use {@link #getOpenTimeout()} and {@link #getReceiveTimeout()} instead * @since 1.1.0 * @return an int representing the open timeout in milliseconds */ @Deprecated public int getTimeout() { return this.openTimeout; } /** * The open timeout associated with the port * * @return an int representing the open timeout in milliseconds * @since 1.2 */ public int getOpenTimeout() { return this.openTimeout; } /** * The receive timeout associated with the port * * @return an int representing the receive timeout in milliseconds * @since 1.2 */ public int getReceiveTimeout() { return this.receiveTimeout; } /** * The {@link String } representing the CommURI */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("comm:").append(this.port).append(";baudrate=").append(this.baudRate).append(";databits=") .append(this.dataBits).append(";stopbits=").append(this.stopBits).append(";parity=") .append(this.parity).append(";flowcontrol=").append(this.flowControl).append(";timeout=") .append(this.openTimeout).append(";receivetimeout=").append(this.receiveTimeout); return sb.toString(); } /** * Converts a String of the CommURI form to a CommURI Object * * @param uri * the {@link String } representing the CommURI * @return a CommURI Object based on the uri String * @throws URISyntaxException */ public static CommURI parseString(String uri) throws URISyntaxException { if (!uri.startsWith("comm:")) { throw new URISyntaxException(uri, "Does not start with comm:"); } // get port int idx = uri.indexOf(";") == -1 ? uri.length() : uri.indexOf(";"); String port = uri.substring(5, idx); Builder builder = new Builder(port); // get params if (idx != uri.length()) { String[] params = uri.substring(idx).split(";"); for (String param : params) { int i = param.indexOf("="); if (i != -1) { String name = param.substring(0, i); String value = param.substring(i + 1); if ("baudrate".equals(name)) { builder = builder.withBaudRate(Integer.parseInt(value)); } else if ("databits".equals(name)) { builder = builder.withDataBits(Integer.parseInt(value)); } else if ("stopbits".equals(name)) { builder = builder.withStopBits(Integer.parseInt(value)); } else if ("parity".equals(name)) { builder = builder.withParity(Integer.parseInt(value)); } else if ("flowcontrol".equals(name)) { builder = builder.withFlowControl(Integer.parseInt(value)); } else if ("timeout".equals(name)) { builder = builder.withOpenTimeout(Integer.parseInt(value)); } else if ("receivetimeout".equals(name)) { builder = builder.withReceiveTimeout(Integer.parseInt(value)); } } } } return builder.build(); } /** * Builder class used as a helper in building the components of a CommURI. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public static class Builder { private final String builderPort; private int builderBaudRate = 19200; private int builderDdataBits = 8; private int builderStopBits = 1; private int builderParity = 0; private int builderFlowControl = 0; private int builderOpenTimeout = 2000; private int builderReceiveTimeout = 0; public Builder(String port) { this.builderPort = port; } public Builder withBaudRate(int baudRate) { this.builderBaudRate = baudRate; return this; } public Builder withDataBits(int dataBits) { this.builderDdataBits = dataBits; return this; } public Builder withStopBits(int stopBits) { this.builderStopBits = stopBits; return this; } public Builder withParity(int parity) { this.builderParity = parity; return this; } public Builder withFlowControl(int flowControl) { this.builderFlowControl = flowControl; return this; } /** * Sets the open timeout associated with the port, this method is identical to {@link #withOpenTimeout(int)} * * @deprecated use {@link #withOpenTimeout(int)} and {@link #withReceiveTimeout(int)} instead * @since 1.1.0 * @param timeout * The open timeout in milliseconds. * @return */ @Deprecated public Builder withTimeout(int timeout) { return withOpenTimeout(timeout); } /** * Sets the open timeout associated with the port * * @param timeout * The open timeout in milliseconds. * @return * @since 1.2 */ public Builder withOpenTimeout(int timeout) { this.builderOpenTimeout = timeout; return this; } /** * Sets the receive timeout associated with the port. Pass 0 to disable the receive timeout. The receive timeout * is disabled by default. * * @param timeout * The receive timeout in milliseconds. * @return * @since 1.2 */ public Builder withReceiveTimeout(int timeout) { this.builderReceiveTimeout = timeout; return this; } public CommURI build() { return new CommURI(this); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/comm/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides services for managing a connection with a serial port. * */ package org.eclipse.kura.comm; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/CommandService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.command; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides methods for running system commands from the web console. * * @deprecated use {@link org.eclipse.kura.executor.CommandExecutorService} * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType @Deprecated public interface CommandService { @Deprecated public String execute(String cmd) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/PasswordCommandService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.command; import org.eclipse.kura.KuraException; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraRequestPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides methods for running system commands from the web console. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface PasswordCommandService { /** * Password protected command execution service * * @param cmd * Command to be executed * @param password * Password as specified in the CommandService * @return String output as returned by the command * @throws KuraException * raised if the command service is disabled, if the password is not correct * or if an internal error occurs */ public String execute(String cmd, String password) throws KuraException; /** * Password protected command execution service * * @param commandReq * Payload containing command information * @return KuraResponsePayload containing the result of the command execution and details on the result * @deprecated */ @Deprecated public default KuraResponsePayload execute(KuraRequestPayload commandReq) { throw new UnsupportedOperationException(); } /** * Password protected command execution service * * @param commandReq * Payload containing command information * @return KuraResponsePayload containing the result of the command execution and details on the result * @throws KuraException * raised if the command execution fails * @since 2.0 */ public KuraPayload execute(KuraPayload commandReq) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/command/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains interface to execute shell commands. * */ package org.eclipse.kura.command; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ComponentConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration; import java.util.Map; import org.eclipse.kura.configuration.metatype.OCD; import org.osgi.annotation.versioning.ProviderType; /** * The ComponentConfiguration groups all the information related to the Configuration of a Component. * It provides access to parsed ObjectClassDefintion associated to this Component. * ComponentConfiguration does not reuse the OSGi ObjectClassDefinition as the latter * does not provide access to certain aspects such as the required attribute, * the min and max values. Instead it returns the raw ObjectClassDefintion as parsed * from the MetaType Information XML resource associated to this Component. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ComponentConfiguration { /** * Returns the PID (service's persistent identity) of the component * associated to this Configuration. * For a component created via {@link ConfigurationService#createFactoryConfiguration(String, String, Map, boolean)} * , * the service's persistent identity is the value of the second parameter of that method; * at runtime, the same value is also available in the {@link ConfigurationService#KURA_SERVICE_PID} * property of one of the configurations of the associated Factory Component. * Otherwise, the service's persistent identity is defined as the name attribute of the * Component Descriptor XML file; at runtime, the same value is also available * in the component.name and in the service.pid properties of the Component Configuration. * If not already specified by the component, the Configuration Service will automatically * set the {@link ConfigurationService#KURA_SERVICE_PID} to the value of service.pid when * the component is first updated. * * @return PID of the component associated to this Configuration. */ public String getPid(); /** * Returns the raw ObjectClassDefinition as parsed from the MetaType * Information XML resource associated to this Component. * * @return */ public OCD getDefinition(); /** * Returns the Dictionary of properties currently used by this component. * * @return the Component's Configuration properties. */ public Map getConfigurationProperties(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ConfigurableComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.configuration; import org.osgi.annotation.versioning.ConsumerType; /** * Marker interface for all Service Component that wants to expose the Configuration through the ConfigurationService. * The Configuration Service tracks all OSGi Components which implement the {@link ConfigurableComponent} marker * interface. *
*
* Important: For a component implementing this interface to be properly tracked by the Configuration Service, * the component must be declared with {@code configurationPolicy = ConfigurationPolicy.REQUIRED} in its * OSGi Declarative Services annotation (or equivalent XML descriptor). Components with * {@code ConfigurationPolicy.OPTIONAL} will not be tracked because they may become active before receiving * a Configuration, and without a service.pid property, the Configuration Service cannot manage them. *
*
* When a ConfigurableComponent is registered, the Configuration Service will call its "update" * method with the latest saved configuration as returned the ConfigurationAdmin or, if none * is available, with the Configuration properties fabricated from the default attribute values as * specified in the ObjectClassDefinition of this service. * In OSGi terms, this process in similar to the Auto Configuration Service. * The ConfigurationService assumes that Meta Type Information XML resource * for a given ConfigurableComponent with name abc" to be stored under OSGI-INF/metatype/abc.xml. * This is an extra restriction over the OSGi specification: the Meta Type Information XML resource * must be named as the name of the Declarative Service Component. *
*/ @ConsumerType public interface ConfigurableComponent { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/ConfigurationService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.configuration; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; import org.osgi.framework.Filter; /** * The Configuration Service is used to manage the configuration of OSGi Declarative Services * implementing the {@link ConfigurableComponent} or the {@link SelfConfiguringComponent} * interface. * It works in concert with the OSGi Configuration Admin and the OSGi Meta Type services. * What it provides over the native OSGi services is the ability to easily access the current * configuration of a Configurable Component or a SelfConfiguring Component together with * their full Meta Type Object Class Definition, * the ability to take snapshots of the current configuration of all managed * services or rollback to older snapshots and, finally, the ability to access * and manage configurations remotely through the Cloud Service. *
*
* The Configuration Service operates on a subset of all the services registered * under the OSGi container. * It tracks only OSGi services which implement the ConfigurableComponent * or the SelfConfiguringComponent interface. *
* Important: For a component implementing {@link ConfigurableComponent} to be properly tracked by the * Configuration Service, the component must be declared with * {@code configurationPolicy = ConfigurationPolicy.REQUIRED} in its OSGi Declarative Services annotation * (or equivalent XML descriptor). Components with {@code ConfigurationPolicy.OPTIONAL} will not be tracked * because they may become active before receiving a Configuration, and without a service.pid property, * the Configuration Service cannot manage them. * Instead, components implementing {@link SelfConfiguringComponent} need to have * {@code configurationPolicy = ConfigurationPolicy.OPTIONAL} unless a configuration for them is seeded * in snapshot_0. *
* More explicitly it does not manage the following services of the OSGi specification: *
    *
  • Managed Service *
  • Managed Service Factory *
  • Component Factory of the Declarative Service specification *
* When a ConfigurableComponent or a SelfConfiguringComponent is tracked, * the Configuration Service will update its Configuration, * as returned by the Configuration Admin, with properties fabricated * from the default attribute values specified in its Meta Type Object Class Definition. *
* The configuration properties will be passed in the activate or update methods * of the Component definition. *
* In OSGi terms, this process in similar to the Auto Configuration Service. *
*
* The Configuration Service assumes the Meta Type Information XML resource * for a given Declarative Service with name "abc" to be stored under OSGI-INF/metatype/abc.xml. *
* This is an extra restriction over the OSGi specification: * the Meta Type Information XML resource * must be named as the name of the Declarative Service Component. *
*
* The Configuration Service has the ability to create a snapshot for the current configuration * of all the tracked components. The snapshot is saved in the form of an * XML file stored under $kura.snapshots/snapshot_epoch.xml where epoch is replaced * with the epoch timestamp at the time of the snapshot creation. * The Configuration Service also has the ability to rollback the configuration of * tracked components taking them back to a previous stored snapshot. *
*
* The Configuration Service also allows creation of new ConfigurableComponents instances * through OSGi Declarative Services by creating a new component Configuration via the OSGi Configuration Admin. * The approach is using * OSGi Declative Services to configure multiple instances of a component. *
*
* In order to manage the configuration of multiple component instances from the same configuration factory, * Kura relies on the following configuration properties: *
    *
  • service.factoryPid is set by the Configuration Admin when the component configuration is first created. * Its value has to match the name of the targeted Declarative Service Component *
  • kura.service.pid is the persistent identity assigned by Kura when the component configuration * is first created calling {@link #createFactoryConfiguration(String, String, Map, boolean)}. *
* Both properties are stored in snapshots to recreate the component instances and restore their configuration * at every framework restart. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ConfigurationService { /** * The name of the the Kura persistent identity property. * * @since 1.0.8 */ public static final String KURA_SERVICE_PID = "kura.service.pid"; /** * Returns the list of Meta Type factory PIDs tracked by the Configuration Service. * * @return the list of Meta Type factory PIDs. * * @since 1.0.8 */ public Set getFactoryComponentPids(); /** * Creates a new ConfigurableComponent instance by creating a new configuration from a * Configuration Admin factory. * The Configuration Service will use the Configuration Admin * to create the component configuration and will update the component configuration with the provided optional * properties. * * @param factoryPid * the ID of the factory. * @param pid * the value of the {@link ConfigurationService#KURA_SERVICE_PID} * that will be set in the component configuration properties. * @param properties * an optional map of properties describing the component configuration. * The Configuration Service will first create an initial map of properties * with the property {@link ConfigurationService#KURA_SERVICE_PID} * set to the provided pid parameter and * with the default component configuration from its OSGi Meta Type. * If properties is not null, the Configuration Service will first remove * {@link ConfigurationService#KURA_SERVICE_PID} * from the provided properties and then it will merge them with the initial map. * @param takeSnapshot * if set to true a snapshot will be taken. * @throws KuraException * if pid is null, it already exists or creation fails. * * @since 1.0.8 */ public void createFactoryConfiguration(String factoryPid, String pid, Map properties, boolean takeSnapshot) throws KuraException; /** * Deletes the ConfigurableComponent instance having the specified PID. * Removes the component configuration and takes a new snapshot. * * @param pid * the PID of the component instance to delete. * @param takeSnapshot * if set to true a snapshot will be taken. * @throws KuraException * if the PID is not found or if the component instance was not created * via {@link #createFactoryConfiguration(String, String, Map, boolean)}. * * @since 1.0.8 */ public void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException; /** * Return the PIDs for all the services that * implements the ConfigurableComponent Maker interface and registered themselves * with the container. * * @return list of PIDs for registered ConfigurableComponents */ public Set getConfigurableComponentPids(); /** * Returns the list of ConfigurableComponents currently registered with the ConfigurationService. * * @return list of registered ConfigurableComponents */ public List getComponentConfigurations() throws KuraException; /** * Returns the list of ConfigurableComponents currently registered with the ConfigurationService that match the * provided OSGi filter. * * @param filter * the filter to be applied * @return list of registered ConfigurableComponents * * @since 2.1 */ public List getComponentConfigurations(Filter filter) throws KuraException; /** * Returns the ComponentConfiguration for the component identified with specified PID. * * @param pid * The ID of the component whose configuration is requested. * @return ComponentConfiguration of the requested Component. */ public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException; /** * Returns the default ComponentConfiguration * for the component having the specified PID. * * @param pid * The ID of the component whose configuration is requested. * @return the ComponentConfiguration of the requested Component. * @throws KuraException * * @since 1.0.8 */ public ComponentConfiguration getDefaultComponentConfiguration(String pid) throws KuraException; /** * Updates the Configuration of the registered component with the specified PID. * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the * component with the specified PID and then sends an update using the * specified properties. *
* If the component to be updated is not yet registered with the ConfigurationService, * it is first registered and then it is updated with the specified properties. * Before updating the component, the specified properties are validated against * the ObjectClassDefinition associated to the Component. The Configuration Service * is fully compliant with the OSGi MetaType Information and the validation happens * through the OSGi MetaType Service. *
* The Configuration Service is compliant with the OSGi MetaType Service so * it accepts all attribute types defined in the OSGi Compendium Specifications. *
* * @param pid * The PID of the component whose configuration is requested. * @param properties * Properties to be used as the new Configuration for the specified Component. * @throws KuraException * if the properties specified do not pass the validation of the ObjectClassDefinition */ public void updateConfiguration(String pid, Map properties) throws KuraException; /** * Updates the Configuration of the registered component with the specified pid. * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the * component with the specified PID and then send an update using the * specified properties. *
* If the component to be updated is not yet registered with the ConfigurationService, * it is first registered and then it is updated with the specified properties. * Before updating the component, the specified properties are validated against * the ObjectClassDefinition associated to the Component. The Configuration Service * is fully compliant with the OSGi MetaType Information and the validation happens * through the OSGi MetaType Service. *
* The Configuration Service is compliant with the OSGi MetaType Service so * it accepts all attribute types defined in the OSGi Compendium Specifications. *
* * @param pid * The PID of the component whose configuration is requested. * @param properties * Properties to be used as the new Configuration for the specified Component. * @param takeSnapshot * defines whether or not this configuration update should trigger a snapshot. * @throws KuraException * if the properties specified do not pass the validation of the ObjectClassDefinition. * * @since 1.0.8 */ public void updateConfiguration(String pid, Map properties, boolean takeSnapshot) throws KuraException; /** * Updates the Configuration of the registered components. * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the * component with the specified PID and then send an update using the * specified properties. *
* If the component to be updated is not yet registered with the ConfigurationService, * it is first registered and then it is updated with the specified properties. * Before updating the component, the specified properties are validated against * the ObjectClassDefinition associated to the Component. The Configuration Service * is fully compliant with the OSGi MetaType Information and the validation happens * through the OSGi MetaType Service. *
* The Configuration Service is compliant with the OSGi MetaType Service so * it accepts all attribute types defined in the OSGi Compendium Specifications. *
* * @param configs * The list of ComponentConfiguration whose update is requested. * @throws KuraException * if the properties specified do not pass the validation of the ObjectClassDefinition */ public void updateConfigurations(List configs) throws KuraException; /** * Updates the Configuration of the registered components. * Using the OSGi ConfigurationAdmin, it retrieves the Configuration of the * component with the specified PID and then send an update using the * specified properties. *
* If the component to be updated is not yet registered with the ConfigurationService, * it is first registered and then it is updated with the specified properties. * Before updating the component, the specified properties are validated against * the ObjectClassDefinition associated to the Component. The Configuration Service * is fully compliant with the OSGi MetaType Information and the validation happens * through the OSGi MetaType Service. *
* The Configuration Service is compliant with the OSGi MetaType Service so * it accepts all attribute types defined in the OSGi Compendium Specifications. *
* * @param configs * The list of ComponentConfiguration whose update is requested. * @param takeSnapshot * defines whether or not this configuration update should trigger a snapshot. * @throws KuraException * if the properties specified do not pass the validation of the ObjectClassDefinition * * @since 1.0.8 */ public void updateConfigurations(List configs, boolean takeSnapshot) throws KuraException; /** * Returns the ID of all the snapshots taken by the ConfigurationService. * The snapshot ID is the epoch time at which the snapshot was taken. * The snapshots are stored in the KuraHome/snapshots/ directory. * This API will return all the snpashot files available in that location. * * @return IDs of the snapshots available. * @throws KuraException */ public Set getSnapshots() throws KuraException; /** * Loads a snapshot given its ID and return the component configurations stored in that snapshot. * * @param sid * - ID of the snapshot to be loaded * @return List of ComponentConfigurations contained in the snapshot * @throws KuraException */ public List getSnapshot(long sid) throws KuraException; /** * Takes a new snapshot of the current configuration of all the registered ConfigurableCompoenents. * It returns the ID of a snapshot as the epoch time at which the snapshot was taken. * * @return the ID of the snapshot. * @throws KuraException */ public long snapshot() throws KuraException; /** * Rolls back to the last saved snapshot if available. * * @return the ID of the snapshot it rolled back to * @throws KuraException * if no snapshots are available or */ public long rollback() throws KuraException; /** * Rolls back to the specified snapshot id. * * @param id * ID of the snapshot we need to rollback to * @throws KuraException * if the snapshot is not found */ public void rollback(long id) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/KuraConfigReadyEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraConfigReadyEvent extends Event { /** Topic of the KuraConfigurationReadyEvent */ public static final String KURA_CONFIG_EVENT_READY_TOPIC = "org/eclipse/kura/configuration/ConfigEvent/READY"; public KuraConfigReadyEvent(Map properties) { super(KURA_CONFIG_EVENT_READY_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/KuraNetConfigReadyEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraNetConfigReadyEvent extends Event { /** Topic of the KuraConfigurationReadyEvent */ public static final String KURA_NET_CONFIG_EVENT_READY_TOPIC = "org/eclipse/kura/configuration/NetConfigEvent/READY"; public KuraNetConfigReadyEvent(Map properties) { super(KURA_NET_CONFIG_EVENT_READY_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/Password.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class Password { private char[] passwordVal; public Password(String password) { super(); if (password != null) { this.passwordVal = password.toCharArray(); } } public Password(char[] password) { super(); this.passwordVal = password; } public char[] getPassword() { return this.passwordVal; } @Override public String toString() { return new String(this.passwordVal); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/SelfConfiguringComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ConsumerType; /** * A SelfConfiguringComponent is a configurable component which maintains its state. * A SelfConfiguringComponent exposes its configuration information to the ConfigurationService * and therefore can be have its configuration updated locally or remotely through the * ConfigurationService APIs. * However, a SelfConfiguringComponent does not rely on the ConfigurationService * to keep the storage of its configuration. The configuration state is kept * internally in the SelfConfiguringComponent or derived at runtime from * other resources such system resources.
* An example of a SelfConfiguringComponent is the NetworkService whose state * is kept in the operating system instead of in the ConfigurationService. */ @ConsumerType public interface SelfConfiguringComponent { /** * This method is called by the ConfigurationService when it requires * the current snapshot of the configuration for this components. * As SelfConfiguringComponents do not rely on the ConfigurationService * to capture and store the current configuration, this call is needed * to expose the current configuration externally and, for example, * being able to store it in snapshot files. * * @return the current configuration for this component * @throws KuraException */ public ComponentConfiguration getConfiguration() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/AD.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Tad complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tad">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Option" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Toption" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="type" use="required" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tscalar" />
 *       <attribute name="cardinality" type="{http://www.w3.org/2001/XMLSchema}int" default="0" />
 *       <attribute name="min" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="max" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="default" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="required" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface AD { /** * Gets the value of the option property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the option property. * *

* For example, to add a new item, do as follows: * *

     * getOption().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Option } * * */ public List

* Java class for Tattribute complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tattribute">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Value" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="adref" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="content" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface Attribute { /** * Gets the value of the value property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the value property. * *

* For example, to add a new item, do as follows: * *

     * getValue().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link String } * * */ public List getValue(); /** * Gets the value of the adref property. * * @return * possible object is * {@link String } * */ public String getAdref(); /** * Gets the value of the content property. * * @return * possible object is * {@link String } * */ public String getContent(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Designate.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Tdesignate complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tdesignate">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Object" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tobject"/>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="pid" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="factoryPid" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="bundle" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="optional" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
 *       <attribute name="merge" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface Designate { /** * Gets the value of the object property. * * @return * possible object is * {@link TObject } * */ public TObject getObject(); /** * Gets the value of the pid property. * * @return * possible object is * {@link String } * */ public String getPid(); /** * Gets the value of the factoryPid property. * * @return * possible object is * {@link String } * */ public String getFactoryPid(); /** * Gets the value of the bundle property. * * @return * possible object is * {@link String } * */ public String getBundle(); /** * Gets the value of the optional property. * * @return * possible object is * {@link Boolean } * */ public boolean isOptional(); /** * Gets the value of the merge property. * * @return * possible object is * {@link Boolean } * */ public boolean isMerge(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Icon.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import java.math.BigInteger; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Ticon complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Ticon">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="resource" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="size" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface Icon { /** * Gets the value of the resource property. * * @return * possible object is * {@link String } * */ public String getResource(); /** * Gets the value of the size property. * * @return * possible object is * {@link BigInteger } * */ public BigInteger getSize(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/MetaData.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Tmetadata complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tmetadata">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="OCD" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tocd" maxOccurs="unbounded" minOccurs="0"/>
 *         <element name="Designate" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tdesignate" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="localization" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface MetaData { /** * Gets the value of the ocd property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the ocd property. * *

* For example, to add a new item, do as follows: * *

     * getOCD().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link OCD } * * */ public List getOCD(); /** * Gets the value of the designate property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the designate property. * *

* For example, to add a new item, do as follows: * *

     * getDesignate().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Designate } * * */ public List getDesignate(); /** * Gets the value of the localization property. * * @return * possible object is * {@link String } * */ public String getLocalization(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/OCD.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Tocd complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tocd">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="AD" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tad" maxOccurs="unbounded"/>
 *         <element name="Icon" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Ticon" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface OCD { /** * Gets the value of the ad property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the ad property. * *

* For example, to add a new item, do as follows: * *

     * getAD().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link AD } * * */ public List getAD(); /** * Gets the value of the icon property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the icon property. * *

* For example, to add a new item, do as follows: * *

     * getIcon().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Icon } * * */ public List getIcon(); /** * Gets the value of the name property. * * @return * possible object is * {@link String } * */ public String getName(); /** * Gets the value of the description property. * * @return * possible object is * {@link String } * */ public String getDescription(); /** * Gets the value of the id property. * * @return * possible object is * {@link String } * */ public String getId(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/OCDService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.configuration.metatype; import java.util.List; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * This Interface provides the capability to get the OCDs for the specified Factories or Service Providers. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.4 */ @ProviderType public interface OCDService { /** * Returns the {@link OCD}s of all registered component factories for which an OSGi MetaType is * is registered in the {@link ConfigurationService}. *
* The {@link OCD}s are returned in the form of a {@link ComponentConfiguration} instance. The component factory pid * can be obtained by calling {@link ComponentConfiguration#getPid()} method and the actual {@link OCD} can be * obtained by calling the {@link ComponentConfiguration#getDefinition()} method. * * * @return The list of the component factory {@link OCD}s. * @since 1.4 */ public List getFactoryComponentOCDs(); /** * Returns the {@link OCD} of the registered component factory identified by the provided {@code factoryPid} and for * which an OSGi MetaType is registered in the {@link ConfigurationService}. *
* The {@link OCD} is returned in the form of a {@link ComponentConfiguration} instance. The component factory pid * can be obtained by calling {@link ComponentConfiguration#getPid()} method and the actual {@link OCD} can be * obtained by calling the {@link ComponentConfiguration#getDefinition()} method. * * @return The {@link OCD} for the requested component factory if available, or null otherwise * @since 1.4 */ public ComponentConfiguration getFactoryComponentOCD(String factoryPid); /** * Searches the Declarative Services layer for Components implementing any of the specified services and returns a * {@link ComponentConfiguration} instance describing it. * If the {@link ConfigurationService} contains a registered OSGi MetaType for a found Component, it will be * returned inside the {@link ComponentConfiguration} instance. *
* The {@link ComponentConfiguration} instances in the returned list contain the following information: *

    *
  • * The {@link ComponentConfiguration#getPid()} method returns the Component name. *
  • *
  • * The {@link ComponentConfiguration#getDefinition()} method returns the {@link OCD} for the found Component if * it is known to the {@link ConfigurationService}, or {@code null} otherwise. *
  • *
* * @param clazzes * The list of service classes to be used as search filter. * @return A list of {@link ComponentConfiguration} instances representing the found Components. * @since 1.4 */ public List getServiceProviderOCDs(Class... classes); /** * @see {@link ConfigurationService#getServiceProviderOCDs(Class...) * * @param classNames * The list of service class or interface names to be used as search filter. * @return A list of {@link ComponentConfiguration} instances representing the found Components. * @since 1.4 */ public List getServiceProviderOCDs(String... classNames); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Option.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Toption complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Toption">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="label" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface Option { /** * Gets the value of the label property. * * @return * possible object is * {@link String } * */ public String getLabel(); /** * Gets the value of the value property. * * @return * possible object is * {@link String } * */ public String getValue(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/Scalar.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.configuration.metatype; /** *

* Java class for Tscalar. * *

* The following schema fragment specifies the expected content contained within this class. *

* *

 * <simpleType name="Tscalar">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="String"/>
 *     <enumeration value="Long"/>
 *     <enumeration value="Double"/>
 *     <enumeration value="Float"/>
 *     <enumeration value="Integer"/>
 *     <enumeration value="Byte"/>
 *     <enumeration value="Char"/>
 *     <enumeration value="Boolean"/>
 *     <enumeration value="Short"/>
 *     <enumeration value="Password"/>
 *   </restriction>
 * </simpleType>
 * 
*/ public enum Scalar { STRING("String"), // LONG("Long"), // DOUBLE("Double"), // FLOAT("Float"), // INTEGER("Integer"), // BYTE("Byte"), // CHAR("Char"), // BOOLEAN("Boolean"), // SHORT("Short"), // PASSWORD("Password"); // private final String value; Scalar(String v) { this.value = v; } public String value() { return this.value; } public static Scalar fromValue(String v) { if ("character".equalsIgnoreCase(v)) { return CHAR; } for (Scalar c : Scalar.values()) { if (c.value.equals(v)) { return c; } } throw new IllegalArgumentException(v); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/TObject.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.configuration.metatype; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** *

* Java class for Tobject complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tobject">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Attribute" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tattribute" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="ocdref" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface TObject { /** * Gets the value of the attribute property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the attribute property. * *

* For example, to add a new item, do as follows: * *

     * getAttribute().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Attribute } * * */ public List getAttribute(); /** * Gets the value of the ocdref property. * * @return * possible object is * {@link String } * */ public String getOcdref(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/metatype/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides expected schemas for JAXB bindings. * */ package org.eclipse.kura.configuration.metatype; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/configuration/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains services to manage all configurable components of the system. This provides an extension to the existing * OSGi MetaTypeService services. * */ package org.eclipse.kura.configuration; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/connection/listener/ConnectionListener.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.connection.listener; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that needs to be notified about connection events. * All registered listeners are called sequentially by the implementations at the occurrence of the * event. * * @since 2.5.0 */ @ConsumerType public interface ConnectionListener { /** * Notifies the listener that the connection has been established. */ public void connected(); /** * Notifies the listener that the connection has been closed. */ public void disconnected(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/connection/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs to implement a ConnectionListener. * * @since 2.5 * */ package org.eclipse.kura.connection.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import static java.util.Objects.requireNonNull; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder; import org.eclipse.kura.container.orchestration.ImageConfiguration.ImageConfigurationBuilder; import org.osgi.annotation.versioning.ProviderType; /** * Object which represents a container configuration used to request the * generation of a new container instance. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.3 * */ @ProviderType public class ContainerConfiguration { private String containerName; private List containerPorts; private List containerEnvVars; private List containerDevices; private Map containerVolumes; private Boolean containerPrivileged; private Boolean isFrameworkManaged = true; private Map containerLoggerParameters; private String containerLoggingType; private ImageConfiguration imageConfig; private ContainerNetworkConfiguration networkConfiguration; private List entryPoint; private Boolean containerRestartOnFailure = false; private Optional memory; private Optional cpus; private Optional gpus; private Optional runtime; private Optional enforcementDigest; private ContainerConfiguration() { } /** * The method will provide information if the container is or not managed by the * framework * * @return true if the framework manages the container. * false otherwise */ public boolean isFrameworkManaged() { return this.isFrameworkManaged; } /** * Returns the container name * * @return */ public String getContainerName() { return this.containerName; } /** * Returns a list of {@link ContainerPort} mapped to the container. * * @return * @since 2.5 */ public List getContainerPorts() { return this.containerPorts; } /** * Returns the list of external ports that will be mapped to the * given container. * * @return * * @deprecated since 2.5. Please use {@link getContainerPorts} as it includes * the network * protocol with the port mapping. */ @Deprecated public List getContainerPortsExternal() { return this.containerPorts.stream().map(ContainerPort::getExternalPort).collect(Collectors.toList()); } /** * Returns the list of internal ports that will be mapped to the * given container * * @return * * @deprecated since 2.5. Please use {@link getContainerPorts} as it includes * the network * protocol with the port mapping. */ @Deprecated public List getContainerPortsInternal() { return this.containerPorts.stream().map(ContainerPort::getInternalPort).collect(Collectors.toList()); } /** * Returns the list of environment properties that will be passed to the * container * * @return */ public List getContainerEnvVars() { return this.containerEnvVars; } /** * Returns the list of devices that will be mapped to the container * * @return */ public List getContainerDevices() { return this.containerDevices; } /** * Returns a map that identifies the volumes and the internal container mapping * * @return */ public Map getContainerVolumes() { return this.containerVolumes; } /** * Returns a boolean representing if the container runs or will run in * privileged mode. * * @return */ public boolean isContainerPrivileged() { return this.containerPrivileged; } /** * Returns a Map that identifies configured logger parameters. * * @return */ public Map getLoggerParameters() { return this.containerLoggerParameters; } /** * Returns a string identifying which logger driver to use. * * @return */ public String getContainerLoggingType() { return this.containerLoggingType; } /** * Returns the {@link ImageConfiguration} object * * @return * @since 2.4 */ public ImageConfiguration getImageConfiguration() { return this.imageConfig; } /** * Returns the base image for the associated container. Detailed image * information can be found in the {@link ImageConfig} class, provided by the * {@link #getImageConfiguration()} method. * * @return */ public String getContainerImage() { return this.imageConfig.getImageName(); } /** * Returns the image tag for the associated container. Detailed image * information can be found in the {@link ImageConfig} class, provided by the * {@link #getImageConfiguration()} method. * * @return */ public String getContainerImageTag() { return this.imageConfig.getImageTag(); } /** * Returns the Registry credentials. Detailed image information can be found in * the {@link ImageConfig} class, provided by the * {@link #getImageConfiguration()} method. * * @return */ public Optional getRegistryCredentials() { return this.imageConfig.getRegistryCredentials(); } /** * Returns the image download timeout (in seconds). Detailed image information * can be found in the {@link ImageConfig} class, provided by the * {@link #getImageConfiguration()} method. * * @return */ public int getImageDownloadTimeoutSeconds() { return this.imageConfig.getimageDownloadTimeoutSeconds(); } /** * return the container's network configuration as a * {@link ContainerNetworkConfiguration}. * * @return * @since 2.4 */ public ContainerNetworkConfiguration getContainerNetworkConfiguration() { return this.networkConfiguration; } /** * Returns a List of container entry points. An empty list can be * returned if no entrypoints are specified. * * @return * @since 2.4 */ public List getEntryPoint() { return this.entryPoint; } /** * Returns boolean which determines if container will restart on failure * * @return * @since 2.4 */ public boolean getRestartOnFailure() { return this.containerRestartOnFailure; } /** * Return the memory to be assigned to the container. * * @return * @since 2.4 */ public Optional getMemory() { return this.memory; } /** * Return the cpus resources to be assigned to the container. * * @return * @since 2.4 */ public Optional getCpus() { return this.cpus; } /** * Return the gpus to be assigned to the container. * * @return * @since 2.4 */ public Optional getGpus() { return this.gpus; } /** * Return the runtime option to be assigned to the container. * * @return the optional runtime string used by the container * @since 2.7 */ public Optional getRuntime() { return this.runtime; } /** * Return the enforcement digest assigned to the container. * * @return the optional runtime string used by the container * @since 2.7 */ public Optional getEnforcementDigest() { return this.enforcementDigest; } /** * Creates a builder for creating a new {@link ContainerConfiguration} instance. * * @return the builder. */ public static ContainerConfigurationBuilder builder() { return new ContainerConfigurationBuilder(); } @Override public int hashCode() { return Objects.hash(this.containerDevices, this.containerEnvVars, this.containerLoggerParameters, this.containerLoggingType, this.containerName, this.containerPorts, this.containerPrivileged, this.containerVolumes, this.cpus, this.enforcementDigest, this.entryPoint, this.gpus, this.imageConfig, this.isFrameworkManaged, this.memory, this.networkConfiguration, this.containerRestartOnFailure, this.runtime); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } ContainerConfiguration other = (ContainerConfiguration) obj; return Objects.equals(this.containerDevices, other.containerDevices) && Objects.equals(this.containerEnvVars, other.containerEnvVars) && Objects.equals(this.containerLoggerParameters, other.containerLoggerParameters) && Objects.equals(this.containerLoggingType, other.containerLoggingType) && Objects.equals(this.containerName, other.containerName) && Objects.equals(this.containerPorts, other.containerPorts) && Objects.equals(this.containerPrivileged, other.containerPrivileged) && Objects.equals(this.containerVolumes, other.containerVolumes) && Objects.equals(this.cpus, other.cpus) && Objects.equals(enforcementDigest, other.enforcementDigest) && Objects.equals(this.entryPoint, other.entryPoint) && Objects.equals(this.gpus, other.gpus) && Objects.equals(this.imageConfig, other.imageConfig) && Objects.equals(this.isFrameworkManaged, other.isFrameworkManaged) && Objects.equals(this.memory, other.memory) && Objects.equals(this.networkConfiguration, other.networkConfiguration) && Objects.equals(this.containerRestartOnFailure, other.containerRestartOnFailure) && Objects.equals(this.runtime, other.runtime); } public static final class ContainerConfigurationBuilder { private String containerName; private List containerPortsExternal = new ArrayList<>(); private List containerPortsInternal = new ArrayList<>(); private List containerPorts = new ArrayList<>(); private List containerEnvVars = new LinkedList<>(); private List containerDevices = new LinkedList<>(); private Map containerVolumes = new HashMap<>(); private Boolean containerPrivileged = false; private Boolean isFrameworkManaged = false; private Map containerLoggerParameters; private String containerLoggingType; private final ImageConfigurationBuilder imageConfigBuilder = new ImageConfiguration.ImageConfigurationBuilder(); private final ContainerNetworkConfigurationBuilder networkConfigurationBuilder = new ContainerNetworkConfigurationBuilder(); private List entryPoint = new LinkedList<>(); private Boolean containerRestartOnFailure = false; private Optional memory = Optional.empty(); private Optional cpus = Optional.empty(); private Optional gpus = Optional.empty(); private Optional runtime = Optional.empty(); private Optional enforcementDigest = Optional.empty(); public ContainerConfigurationBuilder setContainerName(String serviceName) { this.containerName = serviceName; return this; } public ContainerConfigurationBuilder setFrameworkManaged(Boolean isFrameworkManaged) { this.isFrameworkManaged = isFrameworkManaged; return this; } /** * Set a list of {@link ContainerPort}, to express which ports to expose and * what protocol to use. * * @since 2.5 */ public ContainerConfigurationBuilder setContainerPorts(List containerPorts) { this.containerPorts = containerPorts; return this; } /** * Accepts a list of ports to be exposed. Assumes all ports * are TCP. To use other Internet protocols * please see the {@link setContainerPorts} method. Ensure that the * number of elements in this list is the same * as the number of elements set with {@link setInternalPorts}. * * @deprecated since 2.5. Please use {@link setContainerPorts} as it allows for * network protocol to be specified in a port mapping. */ @Deprecated public ContainerConfigurationBuilder setExternalPorts(List containerPortsExternal) { this.containerPortsExternal = new ArrayList<>(containerPortsExternal); return this; } /** * Accepts a list of ports to be open internally within the * container. Assumes all ports are TCP. To * use other Internet protocols please see the * {@link setContainerPorts} method. * Ensure that the number of elements in this list is the same as * the number of elements set with {@link setExternalPorts}. * * @deprecated since 2.5. Please use {@link setContainerPorts} as it allows for * network protocol to be specified in a port mapping. * */ @Deprecated public ContainerConfigurationBuilder setInternalPorts(List containerPortsInternal) { this.containerPortsInternal = new ArrayList<>(containerPortsInternal); return this; } public ContainerConfigurationBuilder setEnvVars(List vars) { this.containerEnvVars = new LinkedList<>(vars); return this; } public ContainerConfigurationBuilder setDeviceList(List devices) { this.containerDevices = new LinkedList<>(devices); return this; } public ContainerConfigurationBuilder setVolumes(Map volumeMap) { this.containerVolumes = new HashMap<>(volumeMap); return this; } public ContainerConfigurationBuilder setLoggerParameters(Map paramMap) { this.containerLoggerParameters = new HashMap<>(paramMap); return this; } public ContainerConfigurationBuilder setLoggingType(String containerLoggingType) { this.containerLoggingType = containerLoggingType; return this; } public ContainerConfigurationBuilder setPrivilegedMode(Boolean containerPrivileged) { this.containerPrivileged = containerPrivileged; return this; } public ContainerConfigurationBuilder setContainerImage(String serviceImage) { this.imageConfigBuilder.setImageName(serviceImage); return this; } public ContainerConfigurationBuilder setContainerImageTag(String serviceImageTag) { this.imageConfigBuilder.setImageTag(serviceImageTag); return this; } public ContainerConfigurationBuilder setRegistryCredentials(Optional registryCredentials) { this.imageConfigBuilder.setRegistryCredentials(registryCredentials); return this; } public ContainerConfigurationBuilder setImageDownloadTimeoutSeconds(int imageDownloadTimeoutSeconds) { this.imageConfigBuilder.setImageDownloadTimeoutSeconds(imageDownloadTimeoutSeconds); return this; } /** * @since 2.4 */ public ContainerConfigurationBuilder setEntryPoint(List entryPoint) { this.entryPoint = entryPoint; return this; } /** * Set the {@link NetworkConfiguration} * * @since 2.4 */ public ContainerConfigurationBuilder setContainerNetowrkConfiguration( ContainerNetworkConfiguration networkConfiguration) { this.networkConfigurationBuilder.setNetworkMode(networkConfiguration.getNetworkMode()); return this; } /** * Set the {@link ImageConfiguration} * * @since 2.4 */ public ContainerConfigurationBuilder setImageConfiguration(ImageConfiguration imageConfig) { this.imageConfigBuilder.setImageName(imageConfig.getImageName()); this.imageConfigBuilder.setImageTag(imageConfig.getImageTag()); this.imageConfigBuilder.setRegistryCredentials(imageConfig.getRegistryCredentials()); this.imageConfigBuilder.setImageDownloadTimeoutSeconds(imageConfig.getimageDownloadTimeoutSeconds()); return this; } /** * Set if container will restart on failure * * @since 2.4 */ public ContainerConfigurationBuilder setRestartOnFailure(boolean containerRestartOnFailure) { this.containerRestartOnFailure = containerRestartOnFailure; return this; } /** * @since 2.4 */ public ContainerConfigurationBuilder setMemory(Optional memory) { this.memory = memory; return this; } /** * @since 2.4 */ public ContainerConfigurationBuilder setCpus(Optional cpus) { this.cpus = cpus; return this; } /** * @since 2.4 */ public ContainerConfigurationBuilder setGpus(Optional gpus) { this.gpus = gpus; return this; } /** * @since 2.7 */ public ContainerConfigurationBuilder setRuntime(Optional runtime) { this.runtime = runtime; return this; } /** * @since 2.7 */ public ContainerConfigurationBuilder setEnforcementDigest(Optional digest) { this.enforcementDigest = digest; return this; } public ContainerConfiguration build() { if (this.containerPorts.isEmpty()) { Iterator extPort = this.containerPortsExternal.iterator(); Iterator intPort = this.containerPortsInternal.iterator(); while (extPort.hasNext() && intPort.hasNext()) { this.containerPorts.add(new ContainerPort(intPort.next(), extPort.next())); } } ContainerConfiguration result = new ContainerConfiguration(); result.containerName = requireNonNull(this.containerName, "Request Container Name cannot be null"); result.containerPorts = this.containerPorts; result.containerEnvVars = this.containerEnvVars; result.containerDevices = this.containerDevices; result.containerVolumes = this.containerVolumes; result.containerPrivileged = this.containerPrivileged; result.isFrameworkManaged = this.isFrameworkManaged; result.containerLoggerParameters = this.containerLoggerParameters; result.containerLoggingType = this.containerLoggingType; result.imageConfig = this.imageConfigBuilder.build(); result.networkConfiguration = this.networkConfigurationBuilder.build(); result.entryPoint = requireNonNull(this.entryPoint, "Container EntryPoint list must not be null"); result.containerRestartOnFailure = this.containerRestartOnFailure; result.memory = this.memory; result.cpus = this.cpus; result.gpus = this.gpus; result.runtime = this.runtime; result.enforcementDigest = this.enforcementDigest; return result; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerInstanceDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import org.osgi.annotation.versioning.ProviderType; /** * Object which represents a instantiated container. Used to track created * containers. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.3 * */ @ProviderType public class ContainerInstanceDescriptor { private String containerName; private String containerImage; private String containerImageTag; private String containerID; private List containerPorts = new ArrayList<>(); private ContainerState containerState = ContainerState.STOPPING; private boolean isFrameworkManaged; private ContainerInstanceDescriptor() { } /** * Returns the container status as {@link ContainerState} * * @return */ public ContainerState getContainerState() { return this.containerState; } /** * The method will provide information if the container is or not managed by the * framework * * @return true if the framework manages the container. * false otherwise */ public boolean isFrameworkManaged() { return this.isFrameworkManaged; } /** * Returns the container name * * @return */ public String getContainerName() { return this.containerName; } /** * Returns the base image for the associated container * * @return */ public String getContainerImage() { return this.containerImage; } /** * Returns the image tag for the associated container * * @return */ public String getContainerImageTag() { return this.containerImageTag; } /** * Returns the containerID * * @return */ public String getContainerId() { return this.containerID; } /** * Returns a list of {@link ContainerPort} mapped to the container. * * @return * @since 2.5 */ public List getContainerPorts() { return this.containerPorts; } /** * Returns the list of external ports that will be mapped to the * given container * * @return * * @deprecated please use {@link getContainerPorts} as it includes the network * protocol with the port mapping. */ @Deprecated public List getContainerPortsExternal() { return this.containerPorts.stream().map(ContainerPort::getExternalPort).collect(Collectors.toList()); } /** * Returns the list of internal ports that will be mapped to the * given container * * @return * * @deprecated please use {@link getContainerPorts} as it includes the network * protocol with the port mapping. * */ @Deprecated public List getContainerPortsInternal() { return this.containerPorts.stream().map(ContainerPort::getInternalPort).collect(Collectors.toList()); } @Override public int hashCode() { return Objects.hash(this.containerID, this.containerImage, this.containerImageTag, this.containerName, this.containerPorts, this.containerState, this.isFrameworkManaged); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } ContainerInstanceDescriptor other = (ContainerInstanceDescriptor) obj; return Objects.equals(this.containerID, other.containerID) && Objects.equals(this.containerImage, other.containerImage) && Objects.equals(this.containerImageTag, other.containerImageTag) && Objects.equals(this.containerName, other.containerName) && Objects.equals(this.containerPorts, other.containerPorts) && this.containerState == other.containerState && this.isFrameworkManaged == other.isFrameworkManaged; } /** * Creates a builder for creating a new {@link ContainerInstanceDescriptor} * instance. * * @return the builder. */ public static ContainerInstanceDescriptorBuilder builder() { return new ContainerInstanceDescriptorBuilder(); } public static final class ContainerInstanceDescriptorBuilder { private String containerName; private String containerImage; private String containerImageTag = "latest"; private String containerId = ""; private List containerPortsExternal = new ArrayList<>(); private List containerPortsInternal = new ArrayList<>(); private List containerPorts = new ArrayList<>(); private ContainerState containerState = ContainerState.STOPPING; private boolean isFrameworkManaged; public ContainerInstanceDescriptorBuilder setContainerName(String serviceName) { this.containerName = serviceName; return this; } public ContainerInstanceDescriptorBuilder setFrameworkManaged(Boolean isFrameworkManaged) { this.isFrameworkManaged = isFrameworkManaged; return this; } public ContainerInstanceDescriptorBuilder setContainerImage(String serviceImage) { this.containerImage = serviceImage; return this; } public ContainerInstanceDescriptorBuilder setContainerImageTag(String serviceImageTag) { this.containerImageTag = serviceImageTag; return this; } public ContainerInstanceDescriptorBuilder setContainerID(String containerID) { this.containerId = containerID; return this; } /** * * Set a list of container ports, to express which ports to expose and what * protocol to use. * * @since 2.5 */ public ContainerInstanceDescriptorBuilder setContainerPorts(List containerPorts) { this.containerPorts = containerPorts; return this; } /** * Accepts a list of ports to be exposed. Assumes all ports * are TCP. To use other Internet protocols * please see the {@link setContainerPorts} method. Ensure that the * number of elements in this list is the same * as the number of elements set with {@link setInternalPorts}. * * @deprecated please use {@link setContainerPorts} as it allows for network * protocol to be specified in a port mapping. * */ @Deprecated public ContainerInstanceDescriptorBuilder setExternalPorts(List containerPortsExternal) { this.containerPortsExternal = new ArrayList<>(containerPortsExternal); return this; } /** * Accepts a list of ports to be open internally within the * container. * Assumes all ports are TCP. To * use other Internet protocols please see the * {@link setContainerPorts} method. * Ensure that the number of elements in this list is the same as * the number of elements set with {@link setExternalPorts}. * * @deprecated please use {@link setContainerPorts} as it allows for network * protocol to be specified in a port mapping. * */ @Deprecated public ContainerInstanceDescriptorBuilder setInternalPorts(List containerPortsInternal) { this.containerPortsInternal = new ArrayList<>(containerPortsInternal); return this; } public ContainerInstanceDescriptorBuilder setContainerState(ContainerState containerState) { this.containerState = containerState; return this; } public ContainerInstanceDescriptor build() { ContainerInstanceDescriptor containerDescriptor = new ContainerInstanceDescriptor(); if (this.containerPorts.isEmpty()) { Iterator extPort = this.containerPortsExternal.iterator(); Iterator intPort = this.containerPortsInternal.iterator(); while (extPort.hasNext() && intPort.hasNext()) { this.containerPorts.add(new ContainerPort(intPort.next(), extPort.next())); } } containerDescriptor.containerName = this.containerName; containerDescriptor.containerImage = this.containerImage; containerDescriptor.containerImageTag = this.containerImageTag; containerDescriptor.containerID = this.containerId; containerDescriptor.containerPorts = this.containerPorts; containerDescriptor.containerState = this.containerState; containerDescriptor.isFrameworkManaged = this.isFrameworkManaged; return containerDescriptor; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerNetworkConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import static java.util.Objects.requireNonNull; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Object which represents a container network configuration used to when * requesting the generation of a new container instance. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.4 * */ @ProviderType public class ContainerNetworkConfiguration { private Optional networkMode; private ContainerNetworkConfiguration() { } /** * * Returns the network mode a container will be created with (e.g. 'bridge', * 'none', 'container:', 'host'). * * @return */ public Optional getNetworkMode() { return this.networkMode; } /** * Creates a builder for creating a new {@link ContainerNetworkConfiguration} * instance. * * @return the builder. */ public static ContainerNetworkConfigurationBuilder builder() { return new ContainerNetworkConfigurationBuilder(); } @Override public int hashCode() { return Objects.hash(this.networkMode); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ContainerNetworkConfiguration)) { return false; } ContainerNetworkConfiguration other = (ContainerNetworkConfiguration) obj; return Objects.equals(this.networkMode, other.networkMode); } public static final class ContainerNetworkConfigurationBuilder { private Optional networkMode = Optional.empty(); public ContainerNetworkConfigurationBuilder setNetworkMode(Optional networkMode) { this.networkMode = networkMode; return this; } public ContainerNetworkConfiguration build() { ContainerNetworkConfiguration result = new ContainerNetworkConfiguration(); result.networkMode = requireNonNull(this.networkMode, "Requested Container Network Mode Name cannot be null"); return result; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerOrchestrationService.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener; import org.osgi.annotation.versioning.ProviderType; /** * Interface for managing the container lifecycle and interacting with the * container manager daemon. * * @since 2.3 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ContainerOrchestrationService { /** * Lists all available containers by id only, like running the cli command 'docker ps -a' * * @return a list of string objects representing the container IDs */ public List listContainersIds(); /** * Lists all available containers returning the corresponding * {@link ContainerInstanceDescriptor}s * * @return a list of {@link ContainerInstanceDescriptor}s representing the * available containers */ public List listContainerDescriptors(); /** * Lists all available images, returning the corresponding * {@link ImageInstanceDescriptor}s * * @return a list of {@link ContainerInstanceDescriptor}s representing the * available containers * @since 2.4 */ public List listImageInstanceDescriptors(); /** * Deletes Image from container engine. Takes ImageID String as parameter. Will * throw an error if image is being used by a container. * * @param imageId string parameter that identifies the image to be deleted * @throws KuraException if the image is used by a container or if the image * deletion process fails * @since 2.4 */ public void deleteImage(String imageId) throws KuraException; /** * Allows to pull the required image, using the specified tag and credentials. * The image will be downloaded respecting the configured timeout in seconds. * * @param imageConfig an ImageConfiguration object which contains info such as * image name, tag, pull timeout in seconds and registry * credentials. * * @throws KuraException if the pull operation fails * @throws InterruptedException * @since 2.4 */ public void pullImage(ImageConfiguration imageConfig) throws KuraException, InterruptedException; /** * Allows to pull the required image, using the specified tag and credentials. * The image will be downloaded respecting the configured timeout in seconds. * * @param imageName the image name to be used. Must not be null. * @param imageTag a string representing the image tag. Must not be * null. * @param timeOutSeconds a non negative integer representing the image * download timeout in seconds * @param registryCredentials an optional that can contain the registry URL and * credentials for authentication * @throws KuraException if the pull operation fails * @throws InterruptedException */ public void pullImage(String imageName, String imageTag, int timeOutSeconds, Optional registryCredentials) throws KuraException, InterruptedException; /** * Returns the id of the container corresponding to the specified name. If no * container can be found an {@link Optional#empty(} result is returned. * * @param name the string representing the container name. Must not be null * @return an {@link Optional} value that will contain the container ID, if the * container exists. Otherwise and {@link Optional#empty()} */ public Optional getContainerIdByName(String name); /** * Starts a container identified by the values provided in a not null * {@link ContainerConfiguration} object. If the requested image does not * exists, it will be downloaded. A String representing the container ID will be * returned if the operation of container creation and start succeed. * * @param containerConfiguration * @return a String representing the container ID created * @throws KuraException is thrown if the image pull or container creation and * start fail */ public String startContainer(ContainerConfiguration containerConfiguration) throws KuraException, InterruptedException; /** * Starts a container identified by the specified ID * * @param id the ID of an already existing container. Must not be null * @throws KuraException if the container starting fails */ public void startContainer(String id) throws KuraException; /** * Stops a container identified by the specified ID * * @param id the ID of an already existing container. Must not be null * @throws KuraException if the container stopping fails */ public void stopContainer(String id) throws KuraException; /** * Deletes a container identified by the specified ID * * @param id the ID of an already existing container. Must not be null * @throws KuraException if the container removal fails */ public void deleteContainer(String id) throws KuraException; /** * Adds a new {@link ContainerOrchestrationServiceListener} * * @param dockerListener * @param containerName */ public void registerListener(ContainerOrchestrationServiceListener dockerListener); /** * Removes the {@link ContainerOrchestrationServiceListener} specified as * parameter * * @param dockerListener */ public void unregisterListener(ContainerOrchestrationServiceListener dockerListener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerPort.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import java.util.Objects; /** * * This class is used to represent a port mapping within a container. * * * @since 2.5 */ public class ContainerPort { private int internalPort; private int externalPort; private PortInternetProtocol internetProtocol; public ContainerPort(int internalPort, int externalPort, PortInternetProtocol internetProtocol) { this.internalPort = internalPort; this.externalPort = externalPort; this.internetProtocol = internetProtocol; } public ContainerPort(int internalPort, int externalPort) { this.internalPort = internalPort; this.externalPort = externalPort; this.internetProtocol = PortInternetProtocol.TCP; } public int getInternalPort() { return internalPort; } public int getExternalPort() { return externalPort; } public PortInternetProtocol getInternetProtocol() { return internetProtocol; } @Override public int hashCode() { return Objects.hash(externalPort, internalPort, internetProtocol); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ContainerPort other = (ContainerPort) obj; return externalPort == other.externalPort && internalPort == other.internalPort && internetProtocol == other.internetProtocol; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ContainerState.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; /** * Enum representing the possible container states as tracked by the orchestrator * * @since 2.3 */ public enum ContainerState { STARTING, INSTALLED, ACTIVE, FAILED, STOPPING; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ImageConfiguration.java ================================================ /*************************************************************************** * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import static java.util.Objects.requireNonNull; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Object which represents an Image configuration used to request the generation * of a new image instance * * @noimplement This interface is not intended to be implemented by clients. * @since 2.4 * */ @ProviderType public class ImageConfiguration { private String imageName; private String imageTag; private Optional registryCredentials; private int imageDownloadTimeoutSeconds = 500; private ImageConfiguration() { } /** * Returns an Image's name as a String. * * @return */ public String getImageName() { return this.imageName; } /** * Returns an Image's tag as a String. * * @return */ public String getImageTag() { return this.imageTag; } /** * Returns an Image's download timeout time as a int. * * @return */ public int getimageDownloadTimeoutSeconds() { return this.imageDownloadTimeoutSeconds; } /** * Returns the Registry credentials * * @return */ public Optional getRegistryCredentials() { return this.registryCredentials; } /** * Creates a builder for creating a new {@link ImageConfiguration} instance. * * @return the builder. */ public static ImageConfigurationBuilder builder() { return new ImageConfigurationBuilder(); } @Override public int hashCode() { return Objects.hash(this.imageName, this.imageTag, this.registryCredentials); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ImageConfiguration)) { return false; } ImageConfiguration other = (ImageConfiguration) obj; return Objects.equals(this.imageName, other.imageName) && Objects.equals(this.imageTag, other.imageTag) && Objects.equals(this.registryCredentials, other.registryCredentials); } public static final class ImageConfigurationBuilder { private String imageName; private String imageTag = "latest"; private Optional registryCredentials; private int imageDownloadTimeoutSeconds = 500; public ImageConfigurationBuilder setImageName(String imageName) { this.imageName = imageName; return this; } public ImageConfigurationBuilder setImageTag(String imageTag) { this.imageTag = imageTag; return this; } public ImageConfigurationBuilder setRegistryCredentials(Optional registryCredentials) { this.registryCredentials = registryCredentials; return this; } public ImageConfigurationBuilder setImageDownloadTimeoutSeconds(int imageDownloadTimeoutSeconds) { this.imageDownloadTimeoutSeconds = imageDownloadTimeoutSeconds; return this; } public ImageConfiguration build() { ImageConfiguration result = new ImageConfiguration(); result.imageName = requireNonNull(this.imageName, "Request Image Name cannot be null"); result.imageTag = this.imageTag; result.registryCredentials = requireNonNull(this.registryCredentials, "Request Registry Credentials object cannot be null."); result.imageDownloadTimeoutSeconds = this.imageDownloadTimeoutSeconds; return result; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/ImageInstanceDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import static java.util.Objects.requireNonNull; import java.util.HashMap; import java.util.Map; import java.util.Objects; import org.osgi.annotation.versioning.ProviderType; /** * Object which represents an image. Used to track created images, and images * that exist in the container engine. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.4 * */ @ProviderType public class ImageInstanceDescriptor { private String imageName = ""; private String imageTag = ""; private String imageId = ""; private String imageAuthor = ""; private String imageArch = ""; private long imageSize = 0; private Map imageLabels = new HashMap<>(); private ImageInstanceDescriptor() { } /** * Returns an Image's name as a String. * * @return */ public String getImageName() { return this.imageName; } /** * Returns an Image's tag as a String. * * @return */ public String getImageTag() { return this.imageTag; } /** * Returns an Image's id as a String. * * @return */ public String getImageId() { return imageId; } /** * Returns an Image's author as a String. * * @return */ public String getImageAuthor() { return imageAuthor; } /** * Returns an Image's architecture as a String. * * @return */ public String getImageArch() { return imageArch; } /** * Returns an Image's size as a long. * * @return */ public long getImageSize() { return imageSize; } /** * Returns all of an Image's tags as a Map. * * @return */ public Map getImageLabels() { return imageLabels; } /** * Creates a builder for creating a new {@link ImageInstanceDescriptor} * instance. * * @return the builder. */ public static ImageInstanceDescriptorBuilder builder() { return new ImageInstanceDescriptorBuilder(); } @Override public int hashCode() { return Objects.hash(this.imageName, this.imageTag, this.imageId, this.imageAuthor, this.imageArch, this.imageSize, this.imageLabels); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ImageInstanceDescriptor)) { return false; } ImageInstanceDescriptor other = (ImageInstanceDescriptor) obj; return Objects.equals(this.imageName, other.imageName) && Objects.equals(this.imageTag, other.imageTag) && Objects.equals(this.imageId, other.imageId) && Objects.equals(this.imageAuthor, other.imageAuthor) && Objects.equals(this.imageArch, other.imageArch) && Objects.equals(this.imageSize, other.imageSize) && Objects.equals(this.imageLabels, other.imageLabels); } public static final class ImageInstanceDescriptorBuilder { private String imageName; private String imageTag; private String imageId; private String imageAuthor; private String imageArch; private long imageSize; private Map imageLabels = new HashMap<>(); public ImageInstanceDescriptorBuilder setImageName(String imageName) { this.imageName = nullToEmpty(imageName); return this; } public ImageInstanceDescriptorBuilder setImageTag(String imageTag) { this.imageTag = nullToEmpty(imageTag); return this; } public ImageInstanceDescriptorBuilder setImageId(String imageId) { this.imageId = nullToEmpty(imageId); return this; } public ImageInstanceDescriptorBuilder setImageAuthor(String imageAuthor) { this.imageAuthor = nullToEmpty(imageAuthor); return this; } public ImageInstanceDescriptorBuilder setImageArch(String imageArch) { this.imageArch = nullToEmpty(imageArch); return this; } public ImageInstanceDescriptorBuilder setimageSize(long imageSize) { this.imageSize = imageSize; return this; } public ImageInstanceDescriptorBuilder setImageLabels(Map imageLabels) { this.imageLabels = imageLabels; return this; } public ImageInstanceDescriptor build() { ImageInstanceDescriptor result = new ImageInstanceDescriptor(); result.imageName = this.imageName; result.imageTag = this.imageTag; result.imageId = requireNonNull(this.imageId, "Image ID cannot be null"); result.imageAuthor = this.imageAuthor; result.imageArch = this.imageArch; result.imageSize = this.imageSize; result.imageLabels = requireNonNull(this.imageLabels, "ImageLabels must not be null"); return result; } private String nullToEmpty(String input) { if (input == null) { return ""; } else { return input; } } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/PasswordRegistryCredentials.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.configuration.Password; /** * Stores the credentials for password authentication to Container Orchestration registry * The password provided is managed as {@link org.eclipse.kura.configuration.Password} and is encrypted by the * {@link org.eclipse.kura.crypto.CryptoService#encryptAes(char[])} * * @since 2.3 */ public class PasswordRegistryCredentials implements RegistryCredentials { private final Optional url; private final String username; private final Password password; public PasswordRegistryCredentials(Optional url, String username, Password password) { super(); this.url = url; this.username = username; this.password = password; } public Optional getUrl() { return this.url; } public String getUsername() { return this.username; } public Password getPassword() { return this.password; } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(this.password.getPassword()), this.url, this.username); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PasswordRegistryCredentials)) { return false; } PasswordRegistryCredentials other = (PasswordRegistryCredentials) obj; return Arrays.equals(this.password.getPassword(), other.password.getPassword()) && Objects.equals(this.url, other.url) && Objects.equals(this.username, other.username); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/PortInternetProtocol.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; /** * * This is an enum containing all supported internet protocols that can be run at a port in a container. * * @since 2.5 * */ public enum PortInternetProtocol { TCP, UDP, SCTP } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/RegistryCredentials.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration; /** * Marker interface for Remote Repository Credentials * * @since 2.3 * */ public interface RegistryCredentials { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/listener/ContainerOrchestrationServiceListener.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration.listener; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that needs to be notified of events in the * {@link org.eclipse.kura.container.orchestration.ContainerOrchestrationService}. * All registered listeners are called synchronously by the * {@link org.eclipse.kura.container.orchestration.ContainerOrchestrationService} at the * occurrence of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. * * @since 2.3 */ @ConsumerType public interface ContainerOrchestrationServiceListener { /** * Notifies the listener that the connection to the orchestrator service is established. */ public void onConnect(); /** * Notifies the listener that the connection to the orchestrator service has been lost. */ public void onDisconnect(); /** * Notifies the listener that the connection to the orchestrator service has been disabled */ public void onDisabled(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides interfaces to listen to notifications from for container orchestrator. */ package org.eclipse.kura.container.orchestration.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/orchestration/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides interfaces for container orchestration. */ package org.eclipse.kura.container.orchestration; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/ContainerSignatureValidationService.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.signature; import org.eclipse.kura.KuraException; import org.eclipse.kura.container.orchestration.ImageInstanceDescriptor; import org.eclipse.kura.container.orchestration.RegistryCredentials; import org.osgi.annotation.versioning.ProviderType; /** * Interface representing a service for validating the signature of a container image * * @since 2.7 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ContainerSignatureValidationService { /** * Verifies the signature of a container image using the provided trust anchor. The trust anchor format depends on * the signature format. For example, if the signature was generated with Cosign, the trust anchor is a ECDSA public * key in PEM format. Other signature formats may require different trust anchors. * * If the signature is not included in a transparency log, the verification will fail unless the * verifyInTransparencyLog is set to false. * * If the image is signed with a different protocol the verification will fail. * * If the device running the verification has no internet access and the signature verification process has no * offline support, the verification will fail. Implementers can choose to throw an exception in this case. * * @param imageName * The image name of the container image to verify. The value will need to be expressed in the form of * registryURL/imagename in case of a custom registry. * @param imageReference * The image tag (e.g. "latest") or the image digest (e.g. "sha256:xxxx") of the container image to * verify. @warning For improved security, it is recommended to use the image digest as input. * @param trustAnchor * The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM * format. The trust anchor is used to verify the signature of the container image. * @param verifyInTransparencyLog * Sets the transparency log verification, to be used when an artifact signature has been uploaded to the * transparency log. Artifacts cannot be publicly verified when not included in a log. * @return {@link:ValidationResult} */ public ValidationResult verify(String imageName, String imageReference, String trustAnchor, boolean verifyInTransparencyLog) throws KuraException; /** * Verifies the signature of a container image using the provided trust anchor and the provided registry * credentials. * The trust anchor format depends on the signature format. For example, if the signature was generated with Cosign, * the trust anchor is a ECDSA public key in PEM format. Other signature formats may require different trust * anchors. * * If the signature is not included in a transparency log, the verification will fail unless the * verifyInTransparencyLog is set to false. * * If the image is signed with a different protocol the verification will fail. * * If the device running the verification has no internet access and the signature verification process has no * offline support, the verification will fail. Likewise if the registry credentials are wrong, the verification * will fail. Implementers can choose to throw an exception in both these cases. * * @param imageName * The image name of the container image to verify. The value will need to be expressed in the form of * registryURL/imagename in case of a custom registry. * @param imageReference * The image tag (e.g. "latest") or the image digest (e.g. "sha256:xxxx") of the container image to * verify. @warning For improved security, it is recommended to use the image digest as input. * @param trustAnchor * The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM * format. The trust anchor is used to verify the signature of the container image. * @param verifyInTransparencyLog * Sets the transparency log verification, to be used when an artifact signature has been uploaded to the * transparency log. Artifacts cannot be publicly verified when not included in a log. * @param credentials * Credentials for registry authentication. If the registry requires authentication, * this needs to be provided to verify the signature. See {@link RegistryCredentials}. * @return {@link:ValidationResult} */ public ValidationResult verify(String imageName, String imageReference, String trustAnchor, boolean verifyInTransparencyLog, RegistryCredentials credentials) throws KuraException; /** * Verifies the signature of a container image using the provided trust anchor. The trust anchor format depends on * the signature format. For example, if the signature was generated with Cosing, the trust anchor is a ECDSA public * key in PEM format. Other signature formats may require different trust anchors. * * If the signature is not included in a transparency log, the verification will fail unless the * verifyInTransparencyLog is set to false. * * If the image is signed with a different protocol the verification will fail. * * If the device running the verification has no internet access and the signature verification process has no * offline support, the verification will fail. Implementers can choose to throw an exception in this case. * * @param imageDescriptor * The image descriptor of the container image to verify (see {@link ImageInstanceDescriptor}) * @param trustAnchor * The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM * format. The trust anchor is used to verify the signature of the container image. * @param verifyInTransparencyLog * Sets the transparency log verification, to be used when an artifact signature has been uploaded to the * transparency log. Artifacts cannot be publicly verified when not included in a log. * @return {@link:ValidationResult} */ public ValidationResult verify(ImageInstanceDescriptor imageDescriptor, String trustAnchor, boolean verifyInTransparencyLog) throws KuraException; /** * Verifies the signature of a container image using the provided trust anchor and the provided registry * credentials. * The trust anchor format depends on the signature format. For example, if the signature was generated with Cosing, * the trust anchor is a ECDSA public key in PEM format. Other signature formats may require different trust * anchors. * * If the signature is not included in a transparency log, the verification will fail unless the * verifyInTransparencyLog is set to false. * * If the image is signed with a different protocol the verification will fail. * * If the device running the verification has no internet access and the signature verification process has no * offline support, the verification will fail. Likewise if the registry credentials are wrong, the verification * will fail. Implementers can choose to throw an exception in both these cases. * * @param imageDescriptor * The image descriptor of the container image to verify (see {@link ImageInstanceDescriptor}) * @param trustAnchor * The trust anchor to use for verification (e.g. a public key or a x509 certificate) typically in PEM * format. The trust anchor is used to verify the signature of the container image. * @param verifyInTransparencyLog * Sets the transparency log verification, to be used when an artifact signature has been uploaded to the * transparency log. Artifacts cannot be publicly verified when not included in a log. * @param credentials * Credentials for registry authentication. If the registry requires authentication, * this needs to be provided to verify the signature. See {@link RegistryCredentials}. * @return {@link:ValidationResult} */ public ValidationResult verify(ImageInstanceDescriptor imageDescriptor, String trustAnchor, boolean verifyInTransparencyLog, RegistryCredentials credentials) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/ValidationResult.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.signature; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Class representing the result of the signature validation performed by {@link:ContainerSignatureValidationService} * * The validation result is composed of two main parts: whether or not the container image signature was * validated and the container image digest (in the "algorithm:encoded" format, @see * Opencontainers specs) * * If the signature is valid, the image digest MUST be provided. * * @since 2.7 */ @ProviderType public final class ValidationResult { private boolean isSignatureValid = false; private Optional imageDigest = Optional.empty(); public ValidationResult() { // Nothing to do } public ValidationResult(boolean signatureValid, String digest) { if (Objects.isNull(signatureValid) || Objects.isNull(digest)) { throw new NullPointerException("Signature results and digest cannot be null."); } if (signatureValid && digest.isEmpty()) { throw new IllegalArgumentException("Image digest must be provided when signature is valid."); } this.imageDigest = Optional.of(digest); this.isSignatureValid = signatureValid; } public boolean isSignatureValid() { return this.isSignatureValid; } public Optional imageDigest() { return this.imageDigest; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ValidationResult other = (ValidationResult) obj; return this.isSignatureValid == other.isSignatureValid && this.imageDigest.equals(other.imageDigest); } @Override public int hashCode() { return Objects.hash(this.isSignatureValid, this.imageDigest); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/container/signature/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides interfaces for container signature verification. */ package org.eclipse.kura.container.signature; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/crypto/CryptoService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.crypto; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * The CryptoService is used to provide AES encrypt and decrypt functionality, Base64 encoding and * decoding, and hash generation. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CryptoService { /** * Returns an AES encrypted char array based on the provided value. * * @param value * A char array that will be encrypted. * @return The char array representing the encrypted value. * @throws KuraException */ public char[] encryptAes(char[] value) throws KuraException; /** * Returns an OutputStream that encrypts provided data using AES in the same way as the encryptAes(char[]) method, * and then writes it to the supplied OutputStream lazily. * * * @param streamToEncrypt * The OutputStream on which the encrypted data will be written. * @return The OutputStream able to encrypt data. * @throws KuraException * @since 3.0 */ public OutputStream aesEncryptingStream(OutputStream destination) throws KuraException; /** * Returns an InputStream that decrypts data obtained from the supplied stream using AES in the same way as the * decryptAes(char[]) method. * * @param streamToDecrypt * The InputStream to read the encrypted data from. * @return InputStream able to decrypt data. * @throws KuraException * @since 3.0 */ public InputStream aesDecryptingStream(InputStream source) throws KuraException; /** * Returns a char array based on the provided encrypted value. * * @param encryptedValue * A char array representing the value to be decrypted. * @return char[] that has been decrypted. * @throws KuraException */ public char[] decryptAes(char[] encryptedValue) throws KuraException; /** * Returns an AES encrypted string based on the provided value. * * @param value * A string that will be encrypted. * @return String that has been encrypted. * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IllegalBlockSizeException * @throws BadPaddingException * @deprecated Use {@link #encryptAes(char[]) instead */ @Deprecated public String encryptAes(String value) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException; /** * Returns a plain text string based on the provided encrypted value. * * @param encryptedValue * A string representing the value to be decrypted. * @return String that has been decrypted. * @throws NoSuchAlgorithmException * @throws NoSuchPaddingException * @throws InvalidKeyException * @throws IOException * @throws IllegalBlockSizeException * @throws BadPaddingException * @deprecated Use {@link #decryptAes(char[])} instead */ @Deprecated public String decryptAes(String encryptedValue) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException; /** * Returns a SHA1 hashed value of the provided string s. * * @param s * A string on which to run the SHA1 hashing algorithm. * @return String that has been hashed. * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException */ default String sha1Hash(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException { return hash(s, "SHA-1"); } /** * Returns a SHA-256 hashed value of the provided string s. * * @param s * A string on which to run the SHA-256 hashing algorithm. * @return String that has been hashed. * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException * @since 2.2 */ default String sha256Hash(String s) throws NoSuchAlgorithmException, UnsupportedEncodingException { return hash(s, "SHA-256"); } /** * Returns an hashed value of the provided string s. * * @param s * A string on which to run the hashing algorithm. * @param algorithm * A String representing the hashing algorithm to be applied * @return String that has been hashed. * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException * @since 2.2 */ public String hash(String s, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException; /** * Returns an encoded string based on the provided stringValue. * * @param stringValue * A string to be encoded. * @return String that has been encoded. * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException */ public String encodeBase64(String stringValue) throws NoSuchAlgorithmException, UnsupportedEncodingException; /** * Returns a decoded string based on the provided encodedValue. * * @param encodedValue * A string to be decoded. * @return String that has been decoded. * @throws NoSuchAlgorithmException * @throws UnsupportedEncodingException */ public String decodeBase64(String encodedValue) throws NoSuchAlgorithmException, UnsupportedEncodingException; /** * Takes a keystore path and returns the corresponding password that can be * used to access to the data saved in the specified keystore. * * @param keyStorePath * A String that represents a unique identifier of the specified keystore. * @return A char array that represents the password of the specified keystore. */ public char[] getKeyStorePassword(String keyStorePath); /** * Takes a keystore path as a String and a char array representing a password * that has to be stored for the specified keystore. * * @param keyStorePath * A String that represents a unique identifier of the specified keystore. * @param password * A char array that represents the password of the specified keystore. * @throws KuraException */ public void setKeyStorePassword(String keyStorePath, char[] password) throws KuraException; /** * Takes a keystore path as a String and a char array representing a password * that has to be stored for the specified keystore. * * @param keyStorePath * A String that represents a unique identifier of the specified keystore. * @param password * A String that represents the password of the specified keystore. * @throws IOException * @deprecated Use {@link #setKeyStorePassword(String, char[])} instead */ @Deprecated public void setKeyStorePassword(String keyStorePath, String password) throws IOException; /** * Answers if the Kura framework is running in security mode. * * @return true if the framework is running in security mode. */ public boolean isFrameworkSecure(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/crypto/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains interfaces to cryptographic functions and used to abstract the effective implementation. * */ package org.eclipse.kura.crypto; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data; import java.util.List; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.KuraTimeoutException; import org.eclipse.kura.data.listener.DataServiceListener; import org.osgi.annotation.versioning.ProviderType; /** * The DataService provides the ability of connecting to a remote * broker, publish messages, subscribe to topics, receive messages on the * subscribed topics, and disconnect from the remote message broker. * The DataService delegates to the {@link DataTransportService} the implementation * of the transport protocol used to interact with the remote server. *
* The DataService offers methods and configuration options to manage the * connection to the remote server. For example, it can be configured * to auto-connect to the remote server on start-up or it offers * methods for applications to directly manage the connection. * It also adds the capability of storing published messages in a persistent store * and send them over the wire at a later time. * The purpose is to relieve service users from implementing their own persistent store. * Service users may publish messages independently on the DataService connection status. *
* In order to overcome the potential latencies introduced by buffering messages, * the DataService allows to assign a priority level to each published message. * Dependently on the store configuration there are certain guarantees that stored * messages are not lost due to sudden crashes or power outages. *
* The whiteboard pattern * is used to notify the service users about events such as message arrived, connection lost etc. * through the {@link DataServiceListener}. * {@see DataServiceListener} * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DataService { /** * Connects to the broker if not already connected. */ public void connect() throws KuraConnectException; /** * Answers if the DataService is connected to the broker. * * @return */ public boolean isConnected(); public boolean isAutoConnectEnabled(); public int getRetryInterval(); /** * Disconnects from the broker. This method will block, up to the specified * duration, allowing the protocol implementation to complete delivery of * in-flight messages before actually disconnecting from the broker. * If the Data Service is configured to auto-connect on startup and it's * explicitly disconnected it will not automatically reconnect. * * @param quiesceTimeout */ public void disconnect(long quiesceTimeout); /** * Subscribes to the specified topic with the remote server. * The method requires an active connection with the remote server and it is operates synchronously. * The implementation is a pass-through to the {@link DataTransportService#subscribe} method. * * @param topic * @param qos * @throws KuraTimeoutException * @throws KuraException * @throws KuraNotConnectedException * TODO */ public void subscribe(String topic, int qos) throws KuraTimeoutException, KuraException, KuraNotConnectedException; /** * Unubscribes to the specified topic with the remote server. * The method requires an active connection with the remote server and it is operates synchronously. * The implementation is a pass-through to the {@link DataTransportService#unsubscribe} method. * * @param topic * @throws KuraTimeoutException * @throws KuraException * @throws KuraNotConnectedException * TODO */ public void unsubscribe(String topic) throws KuraTimeoutException, KuraException, KuraNotConnectedException; /** * Publishes a message to the broker. This method quickly returns deferring * the actual message publication accordingly to the current service policy * and to the specified priority, 0 being the highest. * * Messages are confirmed asynchronously to the caller by the * {@link DataServiceListener#onMessageConfirmed} callback. * * A unique identifier is always returned, independently on the specified * QoS or priority level, which can be used to match the asynchronous * message confirm. * * The actual semantics associated to a message confirm is as follows: *

    *
  • For messages published at QoS = 0, receiving the confirm just means that * the message is about to be transmitted on the wire without any guarantee * that it eventually will. *
  • For messages published at QoS > 0, receiving the confirm means that the * broker acknowledged the message. *
* * Priority level 0 (highest) should be used sparingly and reserved for * messages that should be sent with the minimum latency. * For example Cloud life-cycle messages are published with priority 0 * as soon the connection is established and just before disconnecting. * Priority must be non-negative. *
* Data messages, tolerating an higher latency, may be published with a * lower priority. Within each priority level and each QoS level, messages * are guaranteed do be delivered in order (oldest first). *
* The KuraStoreCapacityReachedException is thrown if the database buffer * has reached its capacity for messages that are not yet published or * they are still in transit. The limit does not apply to internal messages * with the priority less than 2. * These priority levels are reserved to the framework which uses it for life-cycle messages * - birth and death certificates - and replies to request/response flows. * * @param topic * @param payload * @param qos * @param retain * @param priority * @return * @throws KuraStoreException If the message cannot be stored. * @throws IllegalArgumentException If the priority argument is negative. */ public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException; /** * Finds the list of identifiers of messages that have not been published yet. * Given the service has no means of knowing who * published the message, a regex topic must be specified in order to find * only the relevant identifiers. * * * @param topicRegex * @return * @throws KuraStoreException */ List getUnpublishedMessageIds(String topicRegex) throws KuraStoreException; /** * Finds the list of identifiers of messages that are still in-flight * (messages published but not confirmed yet). * This only applies to messages published with QoS > 0. * Given the service has no means of knowing who * published the message, a regex topic must be specified in order to find * only the relevant identifiers. * * @param topicRegex * @return * @throws KuraStoreException */ List getInFlightMessageIds(String topicRegex) throws KuraStoreException; /** * Finds the list of identifiers of in-flight messages that have been dropped. * This only applies to messages published with QoS > 0. * On the establishment of a new connection, the service can be configured * either to republish or drop in-flight messages. * The former option can be used if service users tolerate publishing message * duplicates. * The latter option can be used it service users tolerate losing messages. * Given the service has no means of knowing who * published the message, a regex topic must be specified in order to find * only the relevant identifiers. */ List getDroppedInFlightMessageIds(String topicRegex) throws KuraStoreException; /** * Adds a listener. * * @param listener * * @since 1.0.8 */ public void addDataServiceListener(DataServiceListener listener); /** * Removes a listener. * * @param listener * * @since 1.0.8 */ public void removeDataServiceListener(DataServiceListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataServiceListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data; import org.osgi.annotation.versioning.ConsumerType; /** * Implementors of this interface will be able to handle {@link DataService} * events such as notifications of connection establishing, message arrival, etc. * In order to detect implementors, the {@link DataService} uses the the * whiteboard pattern. *
* All registered listeners are called synchronously by the {@link DataService} at the occurrence of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. * * @deprecated As of {@link org.eclipse.kura.data} 1.1.0, use * {@link DataService#addDataServiceListener(org.eclipse.kura.data.listener.DataServiceListener)} * to register a listener to a DataService. */ @Deprecated @ConsumerType public interface DataServiceListener { /** * Notifies that the DataService has established a connection. */ public void onConnectionEstablished(); /** * Notifies that the DataService is about to cleanly disconnect. If * something needs to be done in reaction to this event, e.g. publishing a * special last message, it SHOULD be done before the method returns. * As soon as the method returns the DataService will start disconnecting. */ public void onDisconnecting(); /** * Notifies that the DataService has cleanly disconnected. */ public void onDisconnected(); /** * Notifies that the DataService has unexpectedly disconnected. */ public void onConnectionLost(Throwable cause); /** * Notifies a message arrival. * * @param topic * @param payload * @param qos * @param retained */ public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained); /** * Notifies the a message has been published. There is no guarantee the * message has been actually transmitted over the wire or that it eventually * will. The only guarantee is that message byte have been passed to the * underlying OS. * * @param messageId */ public void onMessagePublished(int messageId, String topic); /** * Confirms message delivery to the broker. * * @param messageId */ public void onMessageConfirmed(int messageId, String topic); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that needs to be notified of events in the * {@link DataTransportService}. * All registered listeners are called synchronously by the {@link DataTransportService} at the occurrence of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. * * @deprecated As of {@link org.eclipse.kura.data} 1.1.0, use * {@link DataTransportService#addDataTransportListener(org.eclipse.kura.data.transport.listener.DataTransportListener)} * to register a listener to a DataTransportService. */ @Deprecated @ConsumerType public interface DataTransportListener { /** * Notifies the listener of the establishment of the new connection with the remote server. * * @param newSession * true if the connection is to the same broker with the same client ID. */ public void onConnectionEstablished(boolean newSession); /** * Notifies the listener that the connection to the remote server is about to be terminated. */ public void onDisconnecting(); /** * Notifies the listener that the connection to the remote server has been terminated. */ public void onDisconnected(); /** * Notifies the {@link DataTransportService} has received a configuration update. */ public void onConfigurationUpdating(boolean wasConnected); /** * Notifies the {@link DataTransportService} has received a configuration update and it has applied the new * configuration */ public void onConfigurationUpdated(boolean wasConnected); /** * Notifies the listener that the connection to the remote server has been lost. */ public void onConnectionLost(Throwable cause); /** * Notifies the listener that a new message has been received from the remote server. */ public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained); /** * Notifies the listener that a message has been confirmed by the remote server. */ public void onMessageConfirmed(DataTransportToken token); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.KuraTimeoutException; import org.eclipse.kura.KuraTooManyInflightMessagesException; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.osgi.annotation.versioning.ProviderType; /** * DataTransportService implementations provide the ability of connecting to a * remote broker, publish messages, subscribe to topics, receive messages on the * subscribed topics, and disconnect from the remote message broker. * * The whiteboard pattern * is used to notify the service users about events such as message arrived, connection lost etc. * through the {@link DataTransportListener} * * {@see DataTransportListener} * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DataTransportService { /** * Connects to the remote broker. This method will block until the * connection is established or a timeout occurs. The actual configuration * needed to establish a connection is protocol specific (e.g. MQTT) and is * exposed through the ConfigurationAdmin. * * @throws KuraConnectException * the caller MAY retry connecting a later time. */ public void connect() throws KuraConnectException; /** * Returns true if the DataTransportService is currently connected to the remote server. */ public boolean isConnected(); public String getBrokerUrl(); /** * Returns the account name associated with the DataTransportService */ public String getAccountName(); public String getUsername(); public String getClientId(); /** * Disconnects from the broker. This method will block, up to the specified * duration, allowing the protocol implementation to complete delivery of * in-flight messages before actually disconnecting from the broker. * * @param quiesceTimeout * - timeout in milliseconds that will be used before forcing a disconnect */ public void disconnect(long quiesceTimeout); /** * Subscribes to a topic on the broker. This method MAY block until the * underlying protocol message (e.g. the MQTT SUBSCRIBE message) is * acknowledged by the broker or a timeout occurs. This message is * idempotent so the caller may safely retry subscribing. The timeout * interval used by the service is configurable through the * ConfigurationService. * * @param topic * @param qos * @throws KuraTimeoutException * TODO * @throws KuraException * @throws KuraNotConnectedException * TODO */ public void subscribe(String topic, int qos) throws KuraTimeoutException, KuraException, KuraNotConnectedException; /** * Unsubscribes to a topic on the broker. This method MAY block until the * underlying protocol message (e.g. the MQTT UNSUBSCRIBE message) is * acknowledged by the broker or a timeout occurs. The timeout * interval used by the service is configurable through the * ConfigurationService. * * @param topic * @throws KuraTimeoutException * @throws KuraException * @throws KuraNotConnectedException * TODO */ public void unsubscribe(String topic) throws KuraTimeoutException, KuraException, KuraNotConnectedException; /** * Enqueues a message for publishing with the underlying transport implementation. * An active connection to the remote server is required. * * @param topic * @param payload * @param qos * @param retain * @return * @throws KuraTooManyInflightMessagesException * @throws KuraException * @throws KuraNotConnectedException * TODO */ public DataTransportToken publish(String topic, byte[] payload, int qos, boolean retain) throws KuraTooManyInflightMessagesException, KuraException, KuraNotConnectedException; /** * Adds a listener. * * @param listener * * @since 1.0.8 */ public void addDataTransportListener(DataTransportListener listener); /** * Removes a listener. * * @param listener * * @since 1.0.8 */ public void removeDataTransportListener(DataTransportListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/DataTransportToken.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data; import org.osgi.annotation.versioning.ProviderType; /** * DataTransportToken is an receipt returned by the {@link DataTransportService} after the publishing of a message. * Such receipt can be used to track and compare subsequence message confirmation callbacks. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class DataTransportToken { private final int messageId; private final String sessionId; public DataTransportToken(int messageId, String sessionId) { super(); this.messageId = messageId; this.sessionId = sessionId; } public int getMessageId() { return this.messageId; } public String getSessionId() { return this.sessionId; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.messageId; result = prime * result + (this.sessionId == null ? 0 : this.sessionId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DataTransportToken other = (DataTransportToken) obj; if (this.messageId != other.messageId) { return false; } if (this.sessionId == null) { if (other.sessionId != null) { return false; } } else if (!this.sessionId.equals(other.sessionId)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/listener/DataServiceListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data.listener; import org.osgi.annotation.versioning.ConsumerType; /** * Implementors of this interface will be able to handle {@link org.eclipse.kura.data.DataService} * events such as notifications of connection establishing, message arrival, etc. *
* All registered listeners are called synchronously by the {@link org.eclipse.kura.data.DataService} at the occurrence * of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. * * @since 1.0.8 */ @ConsumerType public interface DataServiceListener { /** * Notifies that the DataService has established a connection. */ public void onConnectionEstablished(); /** * Notifies that the DataService is about to cleanly disconnect. If * something needs to be done in reaction to this event, e.g. publishing a * special last message, it SHOULD be done before the method returns. * As soon as the method returns the DataService will start disconnecting. */ public void onDisconnecting(); /** * Notifies that the DataService has cleanly disconnected. */ public void onDisconnected(); /** * Notifies that the DataService has unexpectedly disconnected. */ public void onConnectionLost(Throwable cause); /** * Notifies a message arrival. * * @param topic * @param payload * @param qos * @param retained */ public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained); /** * Notifies the a message has been published. There is no guarantee the * message has been actually transmitted over the wire or that it eventually * will. The only guarantee is that message byte have been passed to the * underlying OS. * * @param messageId */ public void onMessagePublished(int messageId, String topic); /** * Confirms message delivery to the broker. * * @param messageId */ public void onMessageConfirmed(int messageId, String topic); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides interfaces to listen to notifications from the Data Service. */ package org.eclipse.kura.data.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides services for connecting and communicating with a MQTT broker. * */ package org.eclipse.kura.data; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/transport/listener/DataTransportListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.data.transport.listener; import org.eclipse.kura.data.DataTransportToken; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that needs to be notified of events in the * {@link org.eclipse.kura.data.DataTransportService}. * All registered listeners are called synchronously by the {@link org.eclipse.kura.data.DataTransportService} at the * occurrence of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. * * @since 1.0.8 */ @ConsumerType public interface DataTransportListener { /** * Notifies the listener of the establishment of the new connection with the remote server. * * @param newSession * true if the connection is to the same broker with the same client ID. */ public void onConnectionEstablished(boolean newSession); /** * Notifies the listener that the connection to the remote server is about to be terminated. */ public void onDisconnecting(); /** * Notifies the listener that the connection to the remote server has been terminated. */ public void onDisconnected(); /** * Notifies the {@link org.eclipse.kura.data.DataTransportService} has received a configuration update. */ public void onConfigurationUpdating(boolean wasConnected); /** * Notifies the {@link org.eclipse.kura.data.DataTransportService} has received a configuration update and it has * applied the new * configuration */ public void onConfigurationUpdated(boolean wasConnected); /** * Notifies the listener that the connection to the remote server has been lost. */ public void onConnectionLost(Throwable cause); /** * Notifies the listener that a new message has been received from the remote server. */ public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained); /** * Notifies the listener that a message has been confirmed by the remote server. */ public void onMessageConfirmed(DataTransportToken token); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/data/transport/listener/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides interfaces to listen to notifications from the Data Transport Service. */ package org.eclipse.kura.data.transport.listener; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/BaseDbService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.db; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.osgi.annotation.versioning.ProviderType; /** * {@link BaseDbService} offers APIs to acquire and use a JDBC Connection to the embedded SQL database running in the * framework. * The configuration of the {@link BaseDbService} will determine the configuration of the embedded SQL database. * The usage of API is typical for JDBC Connections; the connection is first acquired with getConnection(), * and it must be released when the operation is completed with close(). The implementation of the * DbService and the returned JdbcConnection will manage the concurrent access into the database appropriately. * * @since 1.3 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface BaseDbService { /** * Returns the JDBC Connection to be used to communicate with the embedded SQL database. * For each acquired connection, the DbService.close() method must be called. * * @return Connection to be used * @throws SQLException */ public Connection getConnection() throws SQLException; /** * Releases a previously acquired JDCB connection to the DbService. * * @param conn * to be released */ public void close(Connection conn); /** * Utility method to silently rollback a JDBC Connection without throwing SQLExcepton. * The method will catch any SQLExcepton thrown and log it. */ public void rollback(Connection conn); /** * Utility method to silently close a JDBC ResultSet without throwing SQLExcepton. * The method will catch any SQLExcepton thrown and log it. */ public void close(ResultSet... rss); /** * Utility method to silently close a JDBC Statement without throwing SQLExcepton. * The method will catch any SQLExcepton thrown and log it. */ public void close(Statement... stmts); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/H2DbService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.db; import java.sql.Connection; import java.sql.SQLException; import org.osgi.annotation.versioning.ProviderType; /** * A {@link H2DbService} instance provides an implementation of {@link BaseDbService} using the H2 database engine. * * The Kura core implementation of {@link H2DbService} provides the capability to perform periodic database * defragmentation. * Since H2 currently does not support online defragmentation, the database needs to be shut down to perform the * operation. * * Running the defragmentation will cause the existing connections obtained using the * {@link H2DbService#getConnection()} method to be closed, so applications must be prepared to reopen connections if * necessary. * * As an alternative, it is possible to use the {@link H2DbService#withConnection(ConnectionCallable)} method. * * * @since 1.3 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface H2DbService extends BaseDbService { public static final String DEFAULT_INSTANCE_PID = "org.eclipse.kura.db.H2DbService"; /** * Executes the provided {@link ConnectionCallable} task on the current thread, and returns the result. * It is not necessary to close the {@link Connection} received as argument. If an exception is thrown by the task, * the connection will be rolled back automatically. * * This method guarantees that the execution of the provided task will not be affected by the defragmentation * process. * Performing long running operations in the provided tasks might delay the defragmentation * process. * * @param task * the task to be executed. * @return the result of the executed task. * @throws SQLException * if the provided task throws a {@link SQLException}. * @since 2.0 */ public T withConnection(ConnectionCallable task) throws SQLException; /** * Represents a task that can be executed using the {@link H2DbService#withConnection(ConnectionCallable)} method. * * @param * The return type of the task. * @since 2.0 */ @FunctionalInterface public interface ConnectionCallable { public T call(Connection connection) throws SQLException; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/keyvalue/KeyValueDbService.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.db.keyvalue; import org.eclipse.kura.KuraException; import org.eclipse.kura.connection.listener.ConnectionListener; import org.osgi.annotation.versioning.ProviderType; /** * {@link KeyValueDbService} provides APIs to use the functionalities a of a database capable of storing data in form of key-value pairs. * * @since 2.5.0 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface KeyValueDbService { /** * Adds a {@link ConnectionListener}. * * @param listener * to add * */ public void addListener(ConnectionListener listener); /** * Removes a {@link ConnectionListener} * * @param listener * to remove * */ public void removeListener(ConnectionListener listener); /** * Returns whether the database is connected or not. */ public boolean isConnected(); /** * Set a key with the specified value in the database * * @param key * the key name * @param value * the value of the key as array of byte * @throws KuraException * if the operation is unsuccessful */ void set(String key, byte[] value) throws KuraException; /** * Set a key with the specified value in the database * * @param key * the key name * @param value * the value of the key as a String. The string encondig is platform dependent * @throws KuraException * if the operation is unsuccessful */ void set(String key, String value) throws KuraException; /** * Get a key with the specified value in the database * * @param key * the key name * * @return the key value as byte array * @throws KuraException * if the operation is unsuccessful */ byte[] get(String key) throws KuraException; /** * Get a key with the specified value in the database * * @param key * the key name * * @return the key value as String. The string encondig is platform dependent * @throws KuraException * if the operation is unsuccessful */ String getAsString(String key) throws KuraException; /** * Delete a key with the specified value in the database * * @param key * the key name * * @throws KuraException * if the operation is unsuccessful */ void delete(String key) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/keyvalue/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to use functionalities offered by the key-value databases running in the framework. * */ package org.eclipse.kura.db.keyvalue; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/db/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to acquire and use a JDBC Connection to the embedded SQL database running in the framework. * */ package org.eclipse.kura.db; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/DeploymentHook.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.deployment.hook; import java.util.Map; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ConsumerType; /** *

* This interface can be implemented by a client to define a DEPLOY-V2 Cloudlet hook. * {@link DeploymentHook} instances can be used to customize the behavior of the DEPLOY-V2 * Cloudlet by executing user-defined code at specific stages of deployment requests. *

* *

* A {@link DeploymentHook} implementation must be registered as an OSGi service and it is identified by the * value of the {@code kura.service.pid} service property. *

* *

* In order for a registered hook to be used for a particular request the following conditions must * be verified: *

* *
    *
  • The request must provide a metric named {@code request.type} of string type.
  • *
  • The configuration of the DEPLOY-V2 cloudlet must contain a mapping beetween the received {@code request.type} * and the {@code kura.service.pid} of a registered {@link DeploymentHook} implementation.
  • *
* *

* The associations between {@code request.type} and hook {@code kura.service.pid} are maintained in the configuration * of the DEPLOY-V2 Cloudlet and are modifiable using the Kura WEB Ui. *

* *

* The {@link DeploymentHook} methods can be executed at different stages of the {@code /EXEC/download} and * {@code /EXEC/install} as specified below. *

* * * * * * * * * * * * * * * * * * * * * * *
Method/EXEC/download/EXEC/install
{@link DeploymentHook#preDownload(RequestContext, Map) preDownload()}Called immediately after a valid request is received by the Cloudlet.Never called.
{@link DeploymentHook#postDownload(RequestContext, Map) postDownload()}Called immediately after the download is completed successfully, or immediately after the * {@code preDownload} method is called if the requested file already exists. * When this method is called the requested file should be available on the device.Called immediately after a valid request is received by the Cloudlet, and only if the requested * file is available on the device
{@link DeploymentHook#postInstall(RequestContext, Map) postInstall()}Called immediately after the downloaded deployment package/script has been successfully * installed/executed.Called immediately after the downloaded deployment package/script has been successfully * installed/executed.
* *

* If any of the methods specified by this interface throws an exception, the current request will be aborted. *

* * @since 1.3 */ @ConsumerType public interface DeploymentHook { /** * This method is called at the {@code preDownload} phase, see class description for more details. * * @param context * a {@link RequestContext} instance representing the current DEPLOY-V2 request * @param properties * an hook-specific map of properties * @throws KuraException * if an exception is thrown the current request will be aborted */ public void preDownload(RequestContext context, Map properties) throws KuraException; /** * This method is called at the {@code preDownload} phase, see class description for more details. * * @param context * a {@link RequestContext} instance representing the current DEPLOY-V2 request * @param properties * an hook-specific map of properties * @throws KuraException * if an exception is thrown the current request will be aborted */ public void postDownload(RequestContext context, Map properties) throws KuraException; /** * This method is called at the {@code preDownload} phase, see class description for more details. * * @param context * a {@link RequestContext} instance representing the current DEPLOY-V2 request * @param properties * an hook-specific map of properties * @throws KuraException * if an exception is thrown the current request will be aborted */ public void postInstall(RequestContext context, Map properties) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/RequestContext.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.deployment.hook; import org.osgi.annotation.versioning.ProviderType; /** * This class provides some context information describing a DEPLOY-V2 request. * * @since 1.3 */ @ProviderType public class RequestContext { private final String downloadFilePath; private final String requestType; /** * Creates a new {@link RequestContext} instance. * * @param downloadFilePath * the path of the downloaded file * @param requestType * the value of the {@code request.type} metric contained in the request */ public RequestContext(String downloadFilePath, String requestType) { this.downloadFilePath = downloadFilePath; this.requestType = requestType; } /** * Returns the path of the downloaded file. * * @return the path of the downloaded file */ public String getDownloadFilePath() { return this.downloadFilePath; } /** * Returns the value of the {@code request.type} metric of the request. * * @return the value of the {@code request.type} metric */ public String getRequestType() { return this.requestType; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/deployment/hook/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs that allow to customize the behavior of the DEPLOY-V2 Cloudlet by registering * {@link org.eclipse.kura.deployment.hook.DeploymentHook DeploymentHook} instances. * */ package org.eclipse.kura.deployment.hook; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/ChannelDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.driver; import org.osgi.annotation.versioning.ProviderType; /** * The Interface ChannelDescriptor is mainly used to provide the protocol * specific channel descriptions which will be used by the assets in the Kura * Wires Visualization model. It would enable asset to provide its protocol * specific configurable properties. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface ChannelDescriptor { /** * Returns the protocol specific descriptor. For using drivers in * cooperation with Kura Wires Visualization, the implementors can return * list of {@code AD}s to provide configurable properties for a * {@link org.eclipse.kura.configuration.ConfigurableComponent}.
*
* * This method is essentially needed by Kura Wires Visualization model and * in case the implementors need to use specific driver implementation in * complete isolation, the implementors can return {@code null}.
*
* * Furthermore, some implementors can also provide custom objects. In such * case, implementors must also provide another implementation for providing * configurable properties of a {@link org.eclipse.kura.configuration.ConfigurableComponent} using the * provided custom object. As currently the {@code AD} uses OSGi * Configuration Admin service to provide configurable properties, the * custom object class needs to use OSGi Configuration Admin service for * that same purpose. * * @return the protocol specific descriptor */ public Object getDescriptor(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/Driver.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal * *******************************************************************************/ package org.eclipse.kura.driver; import java.util.List; import java.util.Map; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.channel.listener.ChannelListener; import org.osgi.annotation.versioning.ProviderType; /** * The Interface Driver is the main interface that all Kura specific * communication drivers have to implement and register as an OSGi service * instance. A driver often implements a communication protocol to interact with * the field devices (assets). The configuration as provided to the driver for * communicating with the field device (asset) is provided by user using the * configurable component of the actual driver which is internally managed by * the OSGi Configuration Admin service * * @see ChannelRecord * @see ChannelDescriptor * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface Driver { /** * Each driver is identified by the value of this property in the Component Configuration */ public static final String DRIVER_PID_PROPERTY_NAME = "driver.pid"; /** * The Class ConnectionException is a driver specific exception which is * essentially used to raise exception related to driver connection */ public final class ConnectionException extends Exception { /** The Constant serial version UID. */ private static final long serialVersionUID = 3050873377900124238L; /** * Instantiates a new connection exception. */ public ConnectionException() { super(); } /** * Instantiates a new connection exception. * * @param messsage * the exception message */ public ConnectionException(final String messsage) { super(messsage); } /** * Instantiates a new connection exception. * * @param message * the exception message * @param cause * the exception cause */ public ConnectionException(final String message, final Throwable cause) { super(message, cause); } /** * Instantiates a new connection exception. * * @param cause * the exception cause */ public ConnectionException(final Throwable cause) { super(cause); } } /** * Attempts to connect to the asset. Before performing any * read/write/monitor operation on the connection, a communication channel * has to be opened using this method. If the connection attempt fails it * throws a {@code ConnectionException} * * Some communication protocols are not connection oriented. That means no * connection has to be built up in order to read or write data. In this * case the connect function may optionally test if the asset is reachable. * * @throws ConnectionException * if the connection to the field device is interrupted */ public void connect() throws ConnectionException; /** * Attempts to disconnect the already established communication channel. * * @throws ConnectionException * if the connection to the field device is interrupted */ public void disconnect() throws ConnectionException; /** * Returns the protocol specific channel descriptor. * * @return the channel descriptor */ public ChannelDescriptor getChannelDescriptor(); /** * Reads the communication channels that correspond to the given channel * records. The read result is returned by setting the value in the channel * record. If for some reason no value can be read the value should be set * anyways. In this case the channel flag needs to be specified in the channel * record. The flag shall best describe the reason of failure. If no value * is set the default error code is * {@code DriverFlag#DRIVER_ERROR_UNSPECIFIED}. If the connection to the * asset is interrupted, then any necessary resources that correspond to * this connection should be cleaned up and a {@code ConnectionException} * shall be thrown. * * @param records * the records hold the information of what channels are to be * read. They will be filled by this function with the records * already read. * @throws ConnectionException * if the connection to the field device is interrupted * @throws NullPointerException * if argument is null * @throws IllegalArgumentException * if argument is empty * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the driver then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} */ public void read(List records) throws ConnectionException; /** * Registers channel listener for the provided channel configuration for a * monitor operation on it. * * @param channelConfig * the channel configuration * @param listener * the listener * @throws ConnectionException * if the connection to the field device is interrupted * @throws NullPointerException * any of the arguments is null * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the driver then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} */ public void registerChannelListener(Map channelConfig, ChannelListener listener) throws ConnectionException; /** * Unregisters a already registered channel listener which has been * registered for a monitor operation. * * @param listener * the listener to unregister * @throws ConnectionException * if the connection to the field device is interrupted * @throws NullPointerException * if the argument is null * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the driver then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} */ public void unregisterChannelListener(ChannelListener listener) throws ConnectionException; /** * Writes the data channels that correspond to the given channel records. The * write result is returned by setting the driver flag * {@code ChannelFlag#SUCCESS} in the channel records. If the * connection to the asset is interrupted, then any necessary resources that * correspond to this connection should be cleaned up and a * {@code ConnectionException} shall be thrown. * * @param records * the records hold the information of what channels are to be * written and the values that are to written. They will be * filled by this function with a driver flag stating whether the * write process was successful or not. * @throws ConnectionException * if the connection to the field device is interrupted * @throws NullPointerException * if the argument is null * @throws IllegalArgumentException * if the provided list is empty * @throws org.eclipse.kura.KuraRuntimeException * if the method is not implemented by the driver then specific * error code {@code KuraErrorCode#OPERATION_NOT_SUPPORTED} * needs to be set in the thrown {@link org.eclipse.kura.KuraRuntimeException} */ public void write(List records) throws ConnectionException; /** * This method allows the driver to perform protocol specific optimizations in order to accelerate the execution of * batches of read requests having the same channel configuration. * The result of this optimization will be returned by the driver as a {@link PreparedRead} instance that can be * used to perform the requests. * In order to improve efficiency a driver should validate the channel configuration of the provided channels during * this method call. * It is also permitted to the implementation of the {@link PreparedRead#execute()} and * {@link PreparedRead#getChannelRecords()} methods to return the same {@link ChannelRecord} instances provided as * an * argument to this method. * If the validation of the channel configuration fails for some channels, the driver must not throw an exception * but it is required to return channel records with proper error flags set as a result of the * {@link PreparedRead#execute()} call. * * @see PreparedRead * @param records * The list of channel records that represent the request to be optimized. * @return The {@link PreparedRead} instance * @throws NullPointerException * if the provided list is null */ public PreparedRead prepareRead(List records); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/DriverService.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal * *******************************************************************************/ package org.eclipse.kura.driver; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * The interface DriverService is an utility service API to provide useful * methods for drivers * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 * @deprecated The functionality provided by this service can be replaced by simple calls to OSGi/DS APIs. */ @ProviderType @Deprecated public interface DriverService { /** * Gets the driver instance by the provided driver PID * ({@code kura.service.pid}). * * @param driverPid * the driver PID to check * @return the driver instance * @throws NullPointerException * if the provided driver PID is null */ public Driver getDriver(String driverPid); /** * Gets the driver PID. ({@code kura.service.pid}) by the provided driver * instance * * @param driver * the driver instance to check * @return the driver PID * @throws NullPointerException * if the provided driver instance is null */ public String getDriverPid(Driver driver); /** * Returns the list containing all the available driver instances * * @return the list of drivers available in service registry or empty list if no * drivers are available */ public List listDrivers(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/PreparedRead.java ================================================ /** * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech */ package org.eclipse.kura.driver; import java.util.List; import org.eclipse.kura.KuraException; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.Driver.ConnectionException; import org.osgi.annotation.versioning.ProviderType; /** * This interface represents an optimized request that can be performed by a driver. * Implementations of this interface are returned by a driver as a result of * a call to the {@link Driver#prepareRead(java.util.List)} method. * * @see Driver#prepareRead(java.util.List) * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface PreparedRead extends AutoCloseable { /** * Performs the optimized read request described by this {@link PreparedRead} instance. * In order to improve efficiency this method can return the same {@link ChannelRecord} instances that were supplied * as arguments to the {@link Driver#prepareRead(List)} call that created this {@link PreparedRead}. * The returned records should not be modified while a valid (not closed) {@link PreparedRead} holds a * reference to them, otherwise unpredictable behavior can occur. * * @return the result of the request as a list of {@link ChannelRecord} instances. * @throws KuraException * if the provided {@link PreparedRead} is not valid (for example if it has been closed) * @throws ConnectionException * if the connection to the field device is interrupted */ public List execute() throws ConnectionException, KuraException; /** * Returns the list of channel records associated with this prepared read. * In order to improve efficiency this method can return the same {@link ChannelRecord} instances that were supplied * as arguments to the {@link Driver#prepareRead(List)} call that created this {@link PreparedRead}. * The returned records should not be modified while a valid (not closed) {@link PreparedRead} holds a * reference to them, otherwise unpredictable behavior can occur. * * @return The list of channel records associated with this prepared read. */ public List getChannelRecords(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/DriverDescriptor.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.descriptor; import org.osgi.annotation.versioning.ProviderType; /** * The Class DriverDescriptor is responsible for storing the driver instance * configuration. This class can then be passed for serialization and is used to * map all the information related to a driver instance.
*
* * @see org.eclipse.kura.driver.Driver * @see org.eclipse.kura.driver.ChannelDescriptor * * @noextend This class is not intended to be extended by clients. * @since 1.4 */ @ProviderType public class DriverDescriptor { private final String pid; private final String factoryPid; private final Object channelDescriptor; public DriverDescriptor(String pid, String factoryPid, Object channelDescriptor) { this.pid = pid; this.factoryPid = factoryPid; this.channelDescriptor = channelDescriptor; } public String getPid() { return this.pid; } public String getFactoryPid() { return this.factoryPid; } public Object getChannelDescriptor() { return this.channelDescriptor; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/DriverDescriptorService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.descriptor; import java.util.List; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * The DriverDescriptorService interface is an utility service API to get descriptors for drivers * * @noimplement This interface is not intended to be implemented by clients. * @since 1.4 */ @ProviderType public interface DriverDescriptorService { /** * Returns the {@link DriverDescriptor} corresponding to the Driver instance * identified by the provided Driver {@code kura.service.pid}. * * @param driverPid * the Driver {@code kura.service.pid} that identifies a Driver * Instance * @return the {@link DriverDescriptor} corresponding to the provided method * argument. Or an empty Optional is the provided argument is not a Driver {@code kura.service.pid} * @throws NullPointerException * if the provided driver PID is null * @since 1.4 */ Optional getDriverDescriptor(String driverPid); /** * Returns a list of {@link DriverDescriptor} objects that correspond to the * entire list of Driver Instances in the Framework. * * @return a list of {@link DriverDescriptor} * @since 1.4 */ List listDriverDescriptors(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/descriptor/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ /** * Provides all necessary APIs for Driver Descriptors of Kura Asset Component Model * * @since 1.4 */ package org.eclipse.kura.driver.descriptor; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/driver/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides all necessary APIs for Drivers of Kura Asset Component Model * * @since 1.2 */ package org.eclipse.kura.driver; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Command.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.Map; import org.apache.commons.io.output.NullOutputStream; /** * * The Command class includes the informations needed by the {@link CommandExecutorService} to run a system command. * The only mandatory parameter is the commandLine that represents the command to be run: *
*
*    Command command = new Command("ls -all"); *
*
* Optional parameters are: *
    *
  • directory : the directory where the command is run
  • *
  • environment : a map containing the environment variables needed by the command
  • *
  • out : the output stream representing the output of the command
  • *
  • err : the error stream representing the errors of the command
  • *
  • in : the input stream representing the input of the command
  • *
  • timeout : the timeout in seconds after that the command is stopped. -1 means infinite timeout.
  • *
  • signal : the {@link Signal} sent to the command to stop it after timeout
  • *
  • executeInAShell : a flag that indicates if the command should be executed in a shell/terminal. Default is * false.
  • *
* * @since 2.2 * */ public class Command { private final String[] commandLine; private String directory; private Map environment; private int timeout = -1; private Signal signal; private boolean executeInAShell; private OutputStream out; private OutputStream err; private InputStream in; public Command(String[] commandLine) { this.commandLine = commandLine; this.out = new NullOutputStream(); this.err = new NullOutputStream(); } public String[] getCommandLine() { return this.commandLine; } public String getDirectory() { return this.directory; } public void setDirectory(String directory) { this.directory = directory; } public Map getEnvironment() { return this.environment; } public void setEnvironment(Map environment) { this.environment = environment; } public int getTimeout() { return this.timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public Signal getSignal() { return this.signal; } public void setSignal(Signal signal) { this.signal = signal; } public boolean isExecutedInAShell() { return this.executeInAShell; } public void setExecuteInAShell(boolean executeInAShell) { this.executeInAShell = executeInAShell; } public OutputStream getOutputStream() { return this.out; } public void setOutputStream(OutputStream out) { this.out = out; } public OutputStream getErrorStream() { return this.err; } public void setErrorStream(OutputStream err) { this.err = err; } public InputStream getInputStream() { return this.in; } public void setInputStream(InputStream in) { this.in = in; } @Override public String toString() { return String.join(" ", this.commandLine); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(this.commandLine); result = prime * result + (this.directory == null ? 0 : this.directory.hashCode()); result = prime * result + (this.environment == null ? 0 : this.environment.hashCode()); result = prime * result + (this.executeInAShell ? 1231 : 1237); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } Command other = (Command) obj; if (!Arrays.equals(this.commandLine, other.commandLine)) { return false; } if (this.directory == null) { if (other.directory != null) { return false; } } else if (!this.directory.equals(other.directory)) { return false; } if (this.environment == null) { if (other.environment != null) { return false; } } else if (!this.environment.equals(other.environment)) { return false; } if (this.executeInAShell != other.executeInAShell) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/CommandExecutorService.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import java.util.Map; import java.util.function.Consumer; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides methods for running system processes or executing system commands. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface CommandExecutorService { /** * Synchronously executes a system command. * * @param command * the {@link Command} to be executed * @return a {@link CommandStatus} object */ public CommandStatus execute(Command command); /** * Asynchronously executes a system command. * * @param command * the {@link Command} to be executed * @param callback * the consumer called when the command returns */ public void execute(Command command, Consumer callback); /** * Stops the system process identified by the given {@link Pid}. * * @param pid * the {@link Pid} of the process to be stopped * @param signal * the {@link Signal} sent to the process to stop it. If null, a default signal will be sent. * The type of the default signal is implementation specific * @return a boolean value that is true if the stop operation succeeded */ public boolean stop(Pid pid, Signal signal); /** * Kills the system commands containing all the tokens in the given command line. * If more processes are found, all of them will be killed. * * @param commandLine * the command to be killed * @param signal * the {@link Signal} sent to the command to kill it. If null, a default signal will be sent. * The type of the default signal is implementation specific * @return a boolean value that is true if the kill operation succeeded */ public boolean kill(String[] commandLine, Signal signal); /** * Returns true if the process identified by the given Pid is running. * * @param pid * the {@link Pid} object of the process * @return a boolean value that is true if the process is running */ public boolean isRunning(Pid pid); /** * Returns true if at least one process containing all the tokens in the given command line is found. * It is equivalent to !getPids(commandLine).isEmpty(). * * @param commandLine * the command to be checked * @return a boolean value that is true if the command is running */ public boolean isRunning(String[] commandLine); /** * This method searches for running processes containing all the tokens in the command line. * It returns a map whose keys are the commands found and the values are the associated {@link Pid}s. * * @param commandLine * the command line * @return a map of commands and associated {@link Pid} */ public Map getPids(String[] commandLine); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/CommandStatus.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.io.output.NullOutputStream; /** * * The CommandStatus object is returned by the {@link CommandExecutorService} after the execution of a command. * It contains all the relevant informations about the result of the command execution. *

* The parameters are the following: *

    *
  • command : the command run by the {@link CommandExecutorService}
  • *
  • exitStatus : the {@link ExitStatus} of the command. A value other than 0 means an error. When the command is * stopped by timeout the exit value is 124.
  • *
  • isTimedout : a flag that signals that the command was stopped by timeout
  • *
  • outputStream : the output of the command
  • *
  • errorStream : the error stream of the command
  • *
  • inputStream : the input stream used to send data to the process
  • *
* * @since 2.2 * */ public class CommandStatus { private Command command; private ExitStatus exitStatus; private OutputStream outputStream; private OutputStream errorStream; private InputStream inputStream; private boolean isTimedout; public CommandStatus(Command command, ExitStatus exitStatus) { this.command = command; this.exitStatus = exitStatus; this.outputStream = new NullOutputStream(); this.errorStream = new NullOutputStream(); this.isTimedout = false; } public Command getCommand() { return command; } public void setCommand(Command command) { this.command = command; } public ExitStatus getExitStatus() { return this.exitStatus; } public void setExitStatus(ExitStatus exitStatus) { this.exitStatus = exitStatus; } public OutputStream getErrorStream() { return this.errorStream; } public void setErrorStream(OutputStream errorStream) { this.errorStream = errorStream; } public OutputStream getOutputStream() { return this.outputStream; } public void setOutputStream(OutputStream outputStream) { this.outputStream = outputStream; } public InputStream getInputStream() { return this.inputStream; } public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; } public boolean isTimedout() { return this.isTimedout; } public void setTimedout(boolean isTimedout) { this.isTimedout = isTimedout; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/ExitStatus.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides a method to retrieve the exit status of a system command. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface ExitStatus { /** * Returns a value representing the exit status of a command or process * * @return an integer that represents the exit code */ public int getExitCode(); /** * Returns if a command or process is successful * * @return a boolean that is true if the command is successful, false otherwise */ public boolean isSuccessful(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Pid.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; /** * @since 2.2 */ public interface Pid { public int getPid(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/PrivilegedExecutorService.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import org.osgi.annotation.versioning.ProviderType; /** * This is a marker interface for the {@link CommandExecutorService}. It provides methods for starting system processes * or executing system commands using a privileged user. The privileged user is the same that started Kura, so this * interface provides the highest available level of permissions. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface PrivilegedExecutorService extends CommandExecutorService { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/Signal.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides a method to retrieve the signal to send to system commands or processes (i.e. to kill them). * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface Signal { public int getSignalNumber(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/executor/UnprivilegedExecutorService.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.executor; import org.osgi.annotation.versioning.ProviderType; /** * This is a marker interface for the {@link CommandExecutorService}. It provides methods for starting system processes * or executing system commands using a specific user. The commands are run with the permissions that are granted to * that user. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface UnprivilegedExecutorService extends CommandExecutorService { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/GPIOService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import java.util.List; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; /** * The GPIOService is used to access available GPIO resources on the system.
* {@link KuraGPIOPin}s can be accessed by its name or by its controller and line offset.
*
* Operations on the pins can be done using the acquired {@link KuraGPIOPin} class. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface GPIOService { /** * Get a GPIO pin by its name. * * For example, to get the pin named "GPIO22", call: *
     * KuraGPIOPin pin = gpioService.getPinByName("GPIO22");
     * 
* * @param pinName the name of the pin * * @return the KuraGPIOPin instance * @deprecated Use {@link #getPins(Map)} and select the desired pin from the returned list. */ @Deprecated(since = "3.0", forRemoval = true) public KuraGPIOPin getPinByName(String pinName); /** * Get a GPIO pin by its name, with the specified direction, mode and trigger. * * For example, to get an output open-drain pin with no trigger named "GPIO22", call: *
     * KuraGPIOPin pin = gpioService.getPinByName("GPIO22", KuraGPIODirection.OUTPUT, KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE);
     * 
* * @param pinName the name of the pin * @param direction the direction of the pin * @param mode the mode of the pin * @param trigger the trigger of the pin * * @return the KuraGPIOPin instance * @deprecated Use {@link #getPins(Map, KuraGPIODirection, KuraGPIOMode, KuraGPIOTrigger)} and * select the desired pin from the returned list. */ @Deprecated(since = "3.0", forRemoval = true) public KuraGPIOPin getPinByName(String pinName, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger); /** * Get a GPIO pin by its terminal index. * * @param terminal the terminal index of the pin * * @return the KuraGPIOPin instance * @deprecated Use {@link #getPins(Map)} instead. */ @Deprecated(since = "3.0", forRemoval = true) public KuraGPIOPin getPinByTerminal(int terminal); /** * Get a GPIO pin by its terminal index, with the specified direction, mode and trigger. * * @param terminal the terminal index of the pin * @param direction the direction of the pin * @param mode the mode of the pin * @param trigger the trigger of the pin * * @return the KuraGPIOPin instance * @deprecated Use {@link #getPins(Map, KuraGPIODirection, KuraGPIOMode, KuraGPIOTrigger)} instead. */ @Deprecated(since = "3.0", forRemoval = true) public KuraGPIOPin getPinByTerminal(int terminal, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger); /** * Get a map of available GPIO pins. * * @return a map of available GPIO pins, where the key is the terminal index and the value is the pin name * @deprecated Use {@link #getAvailablePinDescriptions()} instead. */ @Deprecated(since = "3.0", forRemoval = true) public Map getAvailablePins(); /** * Get the GPIO pins that match the given description properties. * * The description map is interpreted as a set of filter criteria: * only the properties present in the map are considered when selecting * pins. Pins that match all provided properties are returned; properties * that are not specified are ignored. * * For example, to get all pins with a specific name, you can call: *
     * Map description = new HashMap<>();
     * description.put("name", "GPIO22");
     * List pins = gpioService.getPins(description);
     * 
* * To get all pins on a specific name and line, you can call: *
     * Map description = new HashMap<>();
     * description.put("name", "GPIO22");
     * description.put("line", "5");
     * List pins = gpioService.getPins(description);
     * 
* * @param description a map of property names to values used to filter pins; may contain * a subset of all supported properties * * @return a list of {@code KuraGPIOPin} instances matching the specified properties * @since 3.0 */ public List getPins(Map description); /** * Get the GPIO pins that match the given description properties, setting the direction, mode and trigger. * * The description map is interpreted as a set of filter criteria: * only the properties present in the map are considered when selecting * pins. Pins that match all provided properties are returned; properties * that are not specified are ignored. * * For example, to get all pins with a specific name, you can call: *
     * Map description = new HashMap<>();
     * description.put("name", "GPIO22");
     * List pins = gpioService.getPins(description, direction, mode, trigger);
     * 
* * To get all pins on a specific name and line, you can call: *
     * Map description = new HashMap<>();
     * description.put("name", "GPIO22");
     * description.put("line", "5");
     * List pins = gpioService.getPins(description, direction, mode, trigger);
     * 
* @param description a map of properties describing the pin * @param direction the direction of the pin * @param mode the mode of the pin * @param trigger the trigger of the pin * * @return a list of KuraGPIOPin instances * @since 3.0 */ public List getPins(Map description, KuraGPIODirection direction, KuraGPIOMode mode, KuraGPIOTrigger trigger); /** * Get the {@link KuraGPIODescription}s of all available GPIO pins. * * @return a list of available GPIO descriptions * @since 3.0 */ public List getAvailablePinDescriptions(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraClosedDeviceException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraClosedDeviceException extends KuraException { /** * */ private static final long serialVersionUID = -1750311704822256084L; public KuraClosedDeviceException(Object argument) { super(KuraErrorCode.CLOSED_DEVICE, null, argument); } public KuraClosedDeviceException(Throwable cause, Object argument) { super(KuraErrorCode.CLOSED_DEVICE, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODescription.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; /** * GPIO description as a set of properties. * * The properties map contains the attributes needed to identify and configure a GPIO pin. * The mandatory DISPLAY_NAME_PROPERTY property is used to get a human readable name for the GPIO pin. * */ public class KuraGPIODescription { public static final String DISPLAY_NAME_PROPERTY = "display.name"; private final Map properties; public KuraGPIODescription(Map properties) { if (properties == null) { throw new IllegalArgumentException("Properties map cannot be null"); } if (!properties.containsKey(DISPLAY_NAME_PROPERTY) || properties.get(DISPLAY_NAME_PROPERTY).isEmpty()) { throw new IllegalArgumentException("Missing mandatory property: " + DISPLAY_NAME_PROPERTY); } this.properties = Collections.unmodifiableMap(new HashMap<>(properties)); } public Map getProperties() { return this.properties; } public String getDisplayName() { return this.properties.get(DISPLAY_NAME_PROPERTY); } @Override public int hashCode() { return Objects.hash(this.properties); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof KuraGPIODescription)) { return false; } KuraGPIODescription other = (KuraGPIODescription) obj; return Objects.equals(this.properties, other.properties); } @Override public String toString() { return "KuraGPIODescription [properties=" + this.properties + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODeviceException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraGPIODeviceException extends KuraException { private static final long serialVersionUID = -1750311704822256084L; public KuraGPIODeviceException(Object argument) { super(KuraErrorCode.GPIO_EXCEPTION, null, argument); } public KuraGPIODeviceException(Throwable cause, Object argument) { super(KuraErrorCode.GPIO_EXCEPTION, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIODirection.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; public enum KuraGPIODirection { INPUT, OUTPUT } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOMode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; public enum KuraGPIOMode { OUTPUT_OPEN_DRAIN, OUTPUT_PUSH_PULL, INPUT_PULL_UP, INPUT_PULL_DOWN } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOPin.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import java.io.IOException; import org.osgi.annotation.versioning.ProviderType; /** * The KuraGPIOPin class is used to access the GPIO resource.
* The pin can be programmed either as an input or as an output. The way this is handled is implementation dependent. *
*
* Pins must be opened and closed before setting or getting values. Implementations, however, could automatically open a * pin if it is closed when accessing it, or automatically close it when it is not needed anymore.
*
* Status of input pins can be retrieved either with a call to {@link #getValue()} or by attaching a * {@link PinStatusListener} * to the pin. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface KuraGPIOPin { /** * Used to set the value of an output pin. * * @param active * New state of the pin. * @throws KuraUnavailableDeviceException * when the GPIO resource is not available * @throws KuraClosedDeviceException * when the GPIO resource has not yet been opened * @throws IOException * if an I/O error occurs */ public void setValue(boolean active) throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException; /** * Used to get the current value of a pin, either output or input * * @return true if the pin is in active state * @throws KuraUnavailableDeviceException * when the GPIO resource is not available * @throws KuraClosedDeviceException * when the GPIO resource has not yet been opened * @throws IOException * if an I/O error occurs */ public boolean getValue() throws KuraUnavailableDeviceException, KuraClosedDeviceException, IOException; /** * Adds a {@link PinStatusListener} to this input pin. The listener will be notified when the status of this input * changes.
* Attaching a listener to an output pin should not raise an exception, but will have no result. * * @param listener * Listener to be added to this pin * @throws KuraClosedDeviceException * when the GPIO resource has not yet been opened * @throws IOException * if an I/O error occurs */ public void addPinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException; /** * Removes a {@link PinStatusListener} from this input pin.
* If the pin has no listeners attached, this method should fail silently.
* * @param listener * Listener to be removed from this pin * @throws KuraClosedDeviceException * when the GPIO resource has not yet been opened * @throws IOException * if an I/O error occurs */ public void removePinStatusListener(PinStatusListener listener) throws KuraClosedDeviceException, IOException; /** * Opens the pin and allocates the needed resources to communicate with it. * * @throws KuraGPIODeviceException * when an exception occurs opening the pin * @throws KuraUnavailableDeviceException * when the GPIO resource is not available * @throws IOException * if a generic I/O error occurs */ public void open() throws KuraGPIODeviceException, KuraUnavailableDeviceException, IOException; /** * Closes this pin and deallocates the resources needed to communicate with it.
*
* If there is a {@link PinStatusListener} attached to this pin, the implementation should remove it * before closing the resource. * * @throws IOException * if a generic I/O error occurs */ public void close() throws IOException; /** * * @return {@link KuraGPIODirection} representing the direction (Input/Output) of the PIN */ public KuraGPIODirection getDirection(); /** * * @return {@link KuraGPIOMode} representing the mode of the pun.
* Open Drain / Push Pull for outputs, Pull Up / Pull Down for inputs. */ public KuraGPIOMode getMode(); /** * * @return {@link KuraGPIOTrigger} representing the trigger mode for this pin. */ public KuraGPIOTrigger getTrigger(); /** * * @return the name associated with the the pin * @deprecated Use {@link #getDescription()} to retrieve pin information. */ @Deprecated(since = "3.0", forRemoval = true) public String getName(); /** * * @return the numeric index of the pin's terminal * @deprecated Use {@link #getDescription()} to retrieve pin information. */ @Deprecated(since = "3.0", forRemoval = true) public int getIndex(); /** * * @return true if the pin has been previously opened for use. */ public boolean isOpen(); /** * * @return the {@link KuraGPIODescription} associated with this pin. * @since 3.0 */ public KuraGPIODescription getDescription(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraGPIOTrigger.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; public enum KuraGPIOTrigger { RAISING_EDGE, FALLING_EDGE, BOTH_EDGES, HIGH_LEVEL, LOW_LEVEL, BOTH_LEVELS, NONE } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/KuraUnavailableDeviceException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraUnavailableDeviceException extends KuraException { private static final long serialVersionUID = -5115093706356681148L; public KuraUnavailableDeviceException(Object argument) { super(KuraErrorCode.UNAVAILABLE_DEVICE, null, argument); } public KuraUnavailableDeviceException(Throwable cause, Object argument) { super(KuraErrorCode.UNAVAILABLE_DEVICE, cause, argument); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/PinStatusListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.gpio; import org.osgi.annotation.versioning.ConsumerType; /** * This interface is used to notify status change on the Input pins * */ @ConsumerType public interface PinStatusListener { /** * Invoked when the status of the attached input pin changes * * @param value * The new value of the pin. */ public void pinStatusChange(boolean value); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/gpio/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to acquire and use GPIO resources available on the system. * */ package org.eclipse.kura.gpio; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/AdditionalConfigurations.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import static java.util.Objects.requireNonNull; import java.util.List; import java.util.Objects; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * Represents a set of additional configurations associated with an identity * managed by {@code IdentityConfigurationExtension} implementations. *
* This class contains a list of {@link ComponentConfiguration} instances, the * {@link ComponentConfiguration#getPid()} method of each configuration should * return the kura.service.pid of the associated * {@code IdentityConfigurationExtension}. *
*
* The {@link IdentityService#getIdentitiesConfiguration(List)} and * {@link IdentityService#getIdentityConfiguration(String, List)} method will * return the {@link ComponentConfiguration}s provided by all * {@code IdentityConfigurationExtension}s registered in the framework. *
*
* The * {@link IdentityService#updateIdentityConfiguration(IdentityConfiguration)} * method * will call * {@code IdentityConfigurationExtension.updateConfiguration(String, ComponentConfiguration)} * method of the {@code IdentityConfigurationExtension} instances whose * kura.service.pid is referenced by the provided configurations. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class AdditionalConfigurations implements IdentityConfigurationComponent { private final List configurations; /** * Creates a new instance containing the provided configuration list. * * @param configurations the configuration list. */ public AdditionalConfigurations(final List configurations) { this.configurations = requireNonNull(configurations, "configuration list cannot be null"); } /** * Returns the list of component configurations. * * @return the list of component configurations. */ public List getConfigurations() { return this.configurations; } @Override public int hashCode() { return Objects.hash(this.configurations); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof AdditionalConfigurations)) { return false; } AdditionalConfigurations other = (AdditionalConfigurations) obj; return Objects.equals(this.configurations, other.configurations); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/AssignedPermissions.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import static java.util.Objects.requireNonNull; import java.util.Objects; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; /** * Describes the the set of permissions currently assigned to a given identity. * If the * {@link IdentityService#updateIdentityConfiguration(IdentityConfiguration)} * receives an {@link IdentityConfiguration} containing this component, it * should replace the currently assigned permission set with the specified one. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class AssignedPermissions implements IdentityConfigurationComponent { private final Set permissions; /** * Creates a new instance representing the provided permission set. * * @param permissions the permission set. */ public AssignedPermissions(final Set permissions) { this.permissions = requireNonNull(permissions, "permissions cannot be null"); } /** * Returns the permission set. * * @return the permission set. */ public Set getPermissions() { return permissions; } @Override public int hashCode() { return Objects.hash(permissions); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof AssignedPermissions)) { return false; } AssignedPermissions other = (AssignedPermissions) obj; return Objects.equals(permissions, other.permissions); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import static java.util.Objects.requireNonNull; import java.util.List; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Describes the configuration for an identity. It is composed by different * {@link IdentityConfigurationComponent}s that can be retrieved and updated * separately using the {@link IdentityService}. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class IdentityConfiguration { private final String name; private final List components; /** * Creates a new identity configuration with the given name and components. * * @param name the identity name. * @param components the {@link IdentityConfigurationComponent} list. */ public IdentityConfiguration(String name, List components) { this.name = requireNonNull(name, "name cannot be null"); if (this.name.trim().isEmpty()) { throw new IllegalArgumentException("name cannot be empty"); } this.components = requireNonNull(components, "components cannot be null"); } /** * Returns the identity name. * * @return the identity name. */ public String getName() { return name; } /** * Returns the list of {@link IdentityConfigurationComponent}s. * * @return the list of {@link IdentityConfigurationComponent}s. */ public List getComponents() { return components; } public Optional getComponent(final Class clazz) { for (final IdentityConfigurationComponent component : components) { if (clazz.isInstance(component)) { return Optional.of(clazz.cast(component)); } } return Optional.empty(); } @Override public int hashCode() { return Objects.hash(components, name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof IdentityConfiguration)) { return false; } IdentityConfiguration other = (IdentityConfiguration) obj; return Objects.equals(components, other.components) && Objects.equals(name, other.name); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityConfigurationComponent.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import org.osgi.annotation.versioning.ProviderType; /** * Represents a portion of the configuration of an identity that can be * retrieved and updated individually. * * The currently supported types are {@link PasswordConfiguration}, * {@link AssignedPermissions} and {@link AdditionalConfigurations}. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.7.0 */ @ProviderType public interface IdentityConfigurationComponent { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/IdentityService.java ================================================ /******************************************************************************* * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.identity; import java.time.Duration; import java.util.List; import java.util.Optional; import java.util.Set; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * A service interface that allows to manage Kura identities. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.7.0 */ @ProviderType public interface IdentityService { /** * Creates a new identity with the given name. * * @param identityName * the name of the identity to be created. * @return {@code true} if the identity with the given name has been created as * part of the method call or {@code false} if the identity already * exists. * @throws KuraException * if a failure occurs in creating the identity. */ public boolean createIdentity(final String identityName) throws KuraException; /** * Creates a new identity using the provided configuration. * * @param identityConfiguration * the identity configuration including identity * name and optional configuration components. * @return {@code true} if the identity with the given name has been created as * part of the method call or {@code false} if the identity already * exists. * @throws KuraException * if a failure occurs in creating the identity. * @since 2.8.0 */ public boolean createIdentity(final IdentityConfiguration identityConfiguration) throws KuraException; /** * Deletes the identity with the given name, including temporary identities. * * @param identityName * the name of the identity to be deleted. * @return {@code true} if the identity with the given name has been deleted as * part of the method call or {@code false} if the identity does not * exist. * @throws KuraException * if a failure occurs in deleting the identity. */ public boolean deleteIdentity(final String identityName) throws KuraException; /** * Returns the configuration of all existing identities. * * @param componentsToReturn * the set of {@link IdentityConfigurationComponent} * types to be returned. If the set is empty a * {@link IdentityConfiguration} will be returned for * each defined identity with an empty component list. * This can be used to get the name for all defined * identities. * * @return the list of {@link IdentityConfiguration}s. An empty list will be * returned if no identities are defined. * @throws KuraException * if a failure occurs in retrieving identity * configurations. */ public List getIdentitiesConfiguration( Set> componentsToReturn) throws KuraException; /** * Returns the configuration of the identity with the given name. * * @param identityName * the identity name. * @param componentsToReturn * the set of {@link IdentityConfigurationComponent} * types to be returned. * @return the configuration of the requested identity or an empty optional if * the identity does not exist. * @throws KuraException * if a failure occurs in retrieving identity * configuration. */ public Optional getIdentityConfiguration(final String identityName, Set> componentsToReturn) throws KuraException; /** * Returns the default configuration for the identity with the given name, this * method should succeed even if the identity does not exist. The result should * be the same configuration returned by the * {@link IdentityService#getIdentityConfiguration(String, Set)} * method for an identity that has just been created with the * {@link IdentityService#createIdentity(String)} method. * * This method can be useful for example to allow a user interface to show the * initial identity configuration to the user before creating it. * * @param identityName * the identity name. * @param componentsToReturn * the set of {@link IdentityConfigurationComponent} * types to be returned. * @return the default configuration for the requested identity * @throws KuraException * if a failure occurs in retrieving identity * configuration. */ public IdentityConfiguration getIdentityDefaultConfiguration(final String identityName, Set> componentsToReturn) throws KuraException; /** * Validates the provided identity configuration without performing any * change to the system. * * @param identityConfiguration * the identity configuration that should be * validated. * @throws KuraException * if the provided identity configuration is not * valid. */ public void validateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException; /** * Updates the configuration of the given identity for the provided * {@link IdentityConfigurationComponent} types. * The configuration of the identities or identity * components that have not been provided will not be modified. * * @param identityConfiguration * the identity configuration that should be * updated. * @throws KuraException * if a failure occurs updating identity * configuration. */ public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException; /** * Defines a new permission. * * @param permission * the permission to be created. * @return {@code true} if the permission has been created as * part of the method call or {@code false} if the permission already * exist. * @throws KuraException * if a failure occurs creating the permission. */ public boolean createPermission(final Permission permission) throws KuraException; /** * Removes an existing permission. The permission will also be removed from all * identities assigned to it. * * @param permission * the permission to be deleted. * @return {@code true} if the permission has been deleted as * part of the method call or {@code false} if the permission does not * exist. * @throws KuraException * if a failure occurs deleting the permission. */ public boolean deletePermission(final Permission permission) throws KuraException; /** * Returns the set of permissions that are currently defined within the * framework. * * @return the set of permissions that are currently defined within the * framework. * @throws KuraException * if a failure occurs retrieving the permission set. */ public Set getPermissions() throws KuraException; /** * Computes a {@link PasswordHash} for the given plaintext password. The * password array will be overwritten at the end of the operation. * * @param password * the plaintext password. * @return the computed password hash. * @throws KuraException * if a failure occurs computing the password hash */ public PasswordHash computePasswordHash(final char[] password) throws KuraException; /** * Checks if the provided password matches the one currently assigned to the * given identity. * * @param identityName * @param password * @throws KuraException * if the passwords do not match of if a failure occurs * while * performing the check. */ public void checkPassword(final String identityName, final char[] password) throws KuraException; /** * Checks if the specified permission is currently assigned to the given * identity. * * @param identityName * @param permission * @throws KuraException * if the provided permission is not currently assigned to * the given identity or if occurs while performing the * check. * */ public void checkPermission(final String identityName, final Permission permission) throws KuraException; /** * Creates a temporary identity that is not persisted and has automatic * expiration. Temporary identities behave like regular identities but are * stored in-memory only and are automatically removed after the specified * lifetime period. * * @param identityName * the name of the temporary identity to create. * @param lifetime * the duration before automatic expiration. The identity * will be automatically removed after this period. * @throws KuraException * if a failure occurs in creating the temporary identity * or if an identity with the given name already exists * (either regular or temporary). * @since 2.8.0 */ public void createTemporaryIdentity(final String identityName, final Duration lifetime) throws KuraException; /** * Creates a temporary identity that is not persisted and has automatic * expiration. Temporary identities behave like regular identities but are * stored in-memory only and are automatically removed after the specified * lifetime period. * * @param identityConfiguration * the identity configuration including identity * name and optional configuration components. * @param lifetime * the duration before automatic expiration. The identity * will be automatically removed after this period. * @throws KuraException * if a failure occurs in creating the temporary identity, * if an identity with the given name already exists * (either regular or temporary) or if the provided configuration * is not valid. * @since 2.8.0 */ public void createTemporaryIdentity(final IdentityConfiguration identityConfiguration, final Duration lifetime) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/LoginBannerService.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * A service interface that provides messages that should be shown to the user * before and/or after login by user interface services (e.g. a web console). * * @noimplement This interface is not intended to be implemented by clients. * @since 3.0.0 */ @ProviderType public interface LoginBannerService { /** * Returns the message that should be shown before user login. * * @return the pre login banner message, or an empty optional if no message should be shown */ public Optional getPreLoginBanner(); /** * Returns the message that should be shown after a successful user login. * * @return the post login banner message, or an empty optional if no message should be shown */ public Optional getPostLoginBanner(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import static java.util.Objects.requireNonNull; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * Describes the password related configuration for an identity. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class PasswordConfiguration implements IdentityConfigurationComponent { private final boolean passwordChangeNeeded; private final boolean passwordAuthEnabled; private final Optional newPassword; private final Optional passwordHash; /** * Creates a new password configuration. * * @param passwordChangeNeeded a {@code boolean} indicating whether a password * change for the given * identity is required at next login. * @param passwordAuthEnabled a {@code boolean} indicating whether a password * authentication is * enabled for the given identity. * @param newPassword a new password that should be set for the given * identity, setting this parameter to empty will * not change the current identity password during a * configuration update. * @param passwordHash the password hash. This value is ignored by the * {@link IdentityService} in case of identity * configuration update. */ public PasswordConfiguration(boolean passwordChangeNeeded, boolean passwordAuthEnabled, Optional newPassword, Optional passwordHash) { this.passwordChangeNeeded = passwordChangeNeeded; this.passwordAuthEnabled = passwordAuthEnabled; this.newPassword = requireNonNull(newPassword, "newPassword cannot be null"); this.passwordHash = requireNonNull(passwordHash, "password hash cannot be null"); } /** * Defines whether a password change is required for the given identity at next * login. * * @return a {@code boolean} indicating whether a password change for the given * identity is required at next login. */ public boolean isPasswordChangeNeeded() { return passwordChangeNeeded; } /** * Defines whether a password authentication is enabled for the given identity. * * @return a {@code boolean} indicating whether a password authentication is * enabled for the given identity. */ public boolean isPasswordAuthEnabled() { return passwordAuthEnabled; } /** * Returns the hash of the password currently associated with the given * identity, if any. * * @return the password hash. */ public Optional getPasswordHash() { return passwordHash; } /** * Returns the new password that should be set for the given identity as part of * a configuration update. The {@link IdentityService} will always return an * empty optional when the password data for an existing identity is retrieved. * * @return the new password. */ public Optional getNewPassword() { return newPassword; } @Override public int hashCode() { return Objects.hash(newPassword, passwordAuthEnabled, passwordChangeNeeded, passwordHash); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PasswordConfiguration)) { return false; } PasswordConfiguration other = (PasswordConfiguration) obj; return Objects.equals(newPassword, other.newPassword) && passwordAuthEnabled == other.passwordAuthEnabled && passwordChangeNeeded == other.passwordChangeNeeded && Objects.equals(passwordHash, other.passwordHash); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordHash.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import org.osgi.annotation.versioning.ProviderType; /** * Represents a password hash computed using an implementation defined * algorithm. The implementation must override the * {@link Object#hashCode()} and {@link Object#equals()} methods. *
*
* Instances of this class can be constructed using the * {@link IdentityService#computePasswordHash(char[])}. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.7.0 */ @ProviderType public interface PasswordHash { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordStrengthRequirements.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import java.util.Objects; import org.osgi.annotation.versioning.ProviderType; /** * Represents a set of password strength requirements that should be enforced by * the framework for new passwords. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class PasswordStrengthRequirements { private final int passwordMinimumLength; private final boolean digitsRequired; private final boolean specialCharactersRequired; private final boolean bothCasesRequired; /** * Creates a new instance. * * @param passwordMinimumLength the minimum allowed password length. * @param digitsRequired a {@code boolean} indicating whether new * passwords must contain * at least one digit. * @param specialCharactersRequired a {@code boolean} indicating whether new * passwords must contain * at least one non alphanumeric character. * @param bothCasesRequired a {@code boolean} indicating whether new * passwords must contain * at least one upper case and lower case * character. */ public PasswordStrengthRequirements(int passwordMinimumLength, boolean digitsRequired, boolean specialCharactersRequired, boolean bothCasesRequired) { this.passwordMinimumLength = passwordMinimumLength; this.digitsRequired = digitsRequired; this.specialCharactersRequired = specialCharactersRequired; this.bothCasesRequired = bothCasesRequired; } /** * Returns the minimum allowed password length. * * @return the minimum allowed password length. */ public int getPasswordMinimumLength() { return passwordMinimumLength; } /** * Returns a {@code boolean} indicating whether new passwords must contain * at least one digit. * * @return a {@code boolean} indicating whether new passwords must contain * at least one digit. */ public boolean digitsRequired() { return digitsRequired; } /** * Returns a {@code boolean} indicating whether new passwords must contain * at least one non alphanumeric character. * * @return a {@code boolean} indicating whether new passwords must contain * at least one non alphanumeric character. */ public boolean specialCharactersRequired() { return specialCharactersRequired; } /** * Returns a {@code boolean} indicating whether new passwords must contain * at least one upper case and lower case character. * * @return a {@code boolean} indicating whether new passwords must contain * at least one upper case and lower case character. */ public boolean bothCasesRequired() { return bothCasesRequired; } @Override public int hashCode() { return Objects.hash(passwordMinimumLength, bothCasesRequired, digitsRequired, specialCharactersRequired); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PasswordStrengthRequirements)) { return false; } PasswordStrengthRequirements other = (PasswordStrengthRequirements) obj; return passwordMinimumLength == other.passwordMinimumLength && bothCasesRequired == other.bothCasesRequired && digitsRequired == other.digitsRequired && specialCharactersRequired == other.specialCharactersRequired; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/PasswordStrengthVerificationService.java ================================================ /******************************************************************************* * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * A service interface that allows to retrieve and verify the password strength * requirements that the framework should enforce for new password. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.7.0 */ @ProviderType public interface PasswordStrengthVerificationService { /** * Checks whether the provided password satisfies the password strength * requirements currently configured on the system. * * @param password * the password to be verified. * @throws KuraException * if the password does not satisfy the current password * strength requirements. */ public void checkPasswordStrength(final char[] password) throws KuraException; /** * Similar to {@link #checkPasswordStrength(char[])} checks whether * the provided password satisfies the password strength requirements currently configured * on the system and in addition verifies that the password * does not match the identityName ignoring the characters case. * * @param identityName * the name of the identity * @param password * the password to be verified. * @since 3.0 * @throws KuraException * if the password does not satisfy the current password * strength requirements. */ public void checkPasswordStrength(String identityName, final char[] password) throws KuraException; /** * Returns the password strength requirements that the framework should enforce * for new passwords. * * @return the password strength requirements. * @throws KuraException * if a failure occurs while retrieving the password * strength requirements. */ public PasswordStrengthRequirements getPasswordStrengthRequirements() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/Permission.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity; import static java.util.Objects.requireNonNull; import java.util.Objects; import org.osgi.annotation.versioning.ProviderType; /** * Represents a permission that can be assigned to Kura identites. * * @noextend This class is not intended to be subclassed by clients. * @since 2.7.0 */ @ProviderType public class Permission { private final String name; /** * Creates a new instance. * * @param name the permission name. */ public Permission(String name) { this.name = requireNonNull(name, "name cannot be null"); } /** * Returns the permission name. * * @return the permission name. */ public String getName() { return name; } @Override public int hashCode() { return Objects.hash(name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Permission)) { return false; } Permission other = (Permission) obj; return Objects.equals(name, other.name); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/configuration/extension/IdentityConfigurationExtension.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.identity.configuration.extension; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * A service interface that can be implemented to provide additional * configuration for Kura identities. The additional configuration can be * retrieved and updated by clients through the {@code IdentityService} using * the {@code AdditionalConfigurations} class. *
*
* Implementing service must be registered with the kura.service.pid property * set to an unique identifier. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.7 */ @ProviderType public interface IdentityConfigurationExtension { /** * Retrieves the default configuration managed by this extension for the * given identity, if any. This method may be called for the given identity name * even if it currently does not exists on the system. *
* The returned configuration should be the same as the one returned by * {@link IdentityConfigurationExtension#getConfiguration(String)} for an * identity that has just been created before that any configuration update is * applied to it. *
* The {@link ComponentConfiguration#getPid()} method of the returned * configuration must be set to the value of the kura.service.pid property of * the extension service. * * * @param identityName the name of the identity. * @return the default additional configuration, or an empty optional. * @throws KuraException if a failure occurs while retrieving the configuration. */ public Optional getDefaultConfiguration(String identityName) throws KuraException; /** * Performs a validation of the provided configuration without applying any * change to the system. This method can be called also for identities that do * not exist on the system yet, * typically this will be done just before creating a new identity. * * @param identityName the name of the identity. * @param configuration the configuration to be validated. * @throws KuraException if the provided configuration is not valid. */ public void validateConfiguration(String identityName, ComponentConfiguration configuration) throws KuraException; /** * Retrieves the additional configuration managed by this extension for the * given identity, if any. *
*
* The {@link ComponentConfiguration#getPid()} method of the returned * configuration must be set to the value of the kura.service.pid property of * the extension service. * * * @param identityName the name of the identity. * @return the additional configuration, or an empty optional. * @throws KuraException if a failure occurs while retrieving the configuration. */ public Optional getConfiguration(String identityName) throws KuraException; /** * Updates the additional configuration managed by this extension for the * given identity. * * @param identityName the name of the identity. * @param configuration the configuration to be applied. * @throws KuraException if a failure occurs while updating the configuration. */ public void updateConfiguration(String identityName, ComponentConfiguration configuration) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/configuration/extension/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs that allow external components to provide additional * custom configuration for Kura identities. * * @since 2.7 */ package org.eclipse.kura.identity.configuration.extension; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/identity/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs to interact with Kura Identities * * @since 2.7 */ package org.eclipse.kura.identity; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/LinuxUdevListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.linux.udev; import org.eclipse.kura.usb.UsbDevice; import org.osgi.annotation.versioning.ConsumerType; @ConsumerType public interface LinuxUdevListener { /** * Callback for notifications of new UsbDevice ATTACH events * * @param device * The UsbDevice that was just attached */ void attached(UsbDevice device); /** * Callback for notifications of new UsbDevice DETACH events * * @param device * The UsbDevice that was just detached */ void detached(UsbDevice device); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/UdevEventType.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.linux.udev; public enum UdevEventType { ATTACHED, DETACHED; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/linux/udev/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides APIs to manage USB devices attached to the system. * */ package org.eclipse.kura.linux.udev; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogEntry.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.log; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * Identifies a device Log message. * * A {@code LogEntry} object contains all the information associated to a device log message. The log message can be * produced by the operating system, the framework, a bundle in the framework or other generic resource. * * @since 2.3 */ @Immutable @ThreadSafe @ProviderType public class LogEntry { private final long timestamp; private final Map properties; /** * Instantiates a new {@link LogEntry} * * @param readProperties * a Map representing the properties in a key-value format */ public LogEntry(Map readProperties) { this(readProperties, 0); } /** * Instantiates a new {@link LogEntry} * * @param readProperties * a Map representing the properties in a key-value format * @param timestamp * a long representing the source timestamp * * @since 2.4 */ public LogEntry(Map readProperties, long timestamp) { requireNonNull(readProperties, "Log properties cannot be null."); this.properties = Collections.unmodifiableMap(readProperties); this.timestamp = timestamp; } /** * Returns the log properties * * @return an unmodifiable Map with the properties associated to this LogEntry instance */ public Map getProperties() { return this.properties; } /** * @since 2.4 */ public long getTimestamp() { return this.timestamp; } @Override public String toString() { return this.properties.toString() + " timestamp: " + this.timestamp; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogProvider.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.log; import org.eclipse.kura.log.listener.LogListener; import org.osgi.annotation.versioning.ProviderType; /** * The LogProvider interface is implemented by all the services responsible to notify {@link LogListener}. * * @noextend This class is not intended to be extended by clients. * @since 2.3 */ @ProviderType public interface LogProvider { /** * Registers a {@link LogListener} that will be notified of new log events * * @param listener * a {@link LogListener} */ public void registerLogListener(LogListener listener); /** * Unregisters a {@link LogListener} from the list of log events listeners * * @param listener * the {@link LogListener} to unregister */ public void unregisterLogListener(LogListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/LogReader.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.log; import org.osgi.annotation.versioning.ProviderType; /** * The LogReader interface is implemented by all the services responsible to read logs from the system, filesystem or * processes running on the system. * * @noextend This class is not intended to be extended by clients. * @since 2.3 */ @ProviderType public interface LogReader extends LogProvider { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/listener/LogListener.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.log.listener; import org.eclipse.kura.log.LogEntry; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that need to be notified of events in the {@link LogProvider}. * * @noextend This class is not intended to be extended by clients. * @since 2.3 */ @ConsumerType public interface LogListener { /** * Notifies the listener that a new log entry has been received. */ public void newLogEntry(LogEntry entry); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/log/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Defines APIs for reading device logs. * * @since 1.0 */ package org.eclipse.kura.log; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Marshaller.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.marshalling; import java.io.OutputStream; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This interface exposes methods for marshalling content * * @noimplement This interface is not intended to be implemented by clients. * @since 1.4 */ @ProviderType public interface Marshaller { /** * Returns a {@link String} that represents the {@link Object} passed as input. * * @param object * the object that will be marshalled. * @return a {@link String} representing the string representation of the object passed as input * @throws KuraException * when the marshalling operation fails. */ public String marshal(Object object) throws KuraException; /** * Serialises the provided {@link Object} and writes the result to the supplied {@link OutputStream} * * @param out * the {@link OutputStream} on which the data will be written * @param object * the {@link Object} that will be marshalled. * @throws KuraException * @since 3.0 */ public void marshal(final OutputStream out, Object object) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Unmarshaller.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.marshalling; import java.io.InputStream; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This interface exposes methods for unmarshalling content * * @noimplement This interface is not intended to be implemented by clients. * @since 1.4 */ @ProviderType public interface Unmarshaller { /** * This method takes a String representation and a class that will be used as reference to construct the result. * * @param string * the input string * @param clazz * the class representing the type of object expected for the result * @return an object that is constructed from the passed string * @throws KuraException * when the unmarshaling operation fails. */ public T unmarshal(String string, Class clazz) throws KuraException; /** * Deserialises an object of the specified type from the provided {@link InputStream} * * @param in * the input stream * @param clazz * the class representing the type of object expected for the result * @return an object that is constructed from the passed string * @throws KuraException * when the unmarshaling operation fails. * @since 3.0 */ public T unmarshal(InputStream in, Class clazz) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * APIs for all the marshaller/unmarshaller services */ package org.eclipse.kura.marshalling; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertPayload.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.osgi.annotation.versioning.ProviderType; /** * @since 2.0 * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraAlertPayload extends KuraPayload { public static final String CODE_METRIC_NAME = "alert_code"; public static final String SEVERITY_METRIC_NAME = "alert_severity"; public static final String STATUS_METRIC_NAME = "alert_status"; public static final String MESSAGE_METRIC_NAME = "alert_message"; public static final String CREATION_TIMESTAMP_METRIC_NAME = "alert_creation_date"; private static final DateFormat DATE_FORMAT = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy"); public KuraAlertPayload(final String code, final KuraAlertSeverity severity, final KuraAlertStatus status) { setCode(code); setSeverity(severity); setStatus(status); } public void setCode(final String code) { super.addMetric(CODE_METRIC_NAME, validateCode(code)); } public void setSeverity(final KuraAlertSeverity severity) { super.addMetric(SEVERITY_METRIC_NAME, severity.name()); } public void setStatus(final KuraAlertStatus status) { super.addMetric(STATUS_METRIC_NAME, status.name()); } public void setCreationTimestamp(final Date date) { super.addMetric(CREATION_TIMESTAMP_METRIC_NAME, date.toString()); } public void setMessage(final String message) { if (message == null) { super.removeMetric(MESSAGE_METRIC_NAME); } else { super.addMetric(MESSAGE_METRIC_NAME, message); } } public String getCode() { return (String) getMetric(CODE_METRIC_NAME); } public KuraAlertSeverity getSeverity() { return KuraAlertSeverity.valueOf((String) getMetric(SEVERITY_METRIC_NAME)); } public KuraAlertStatus getStatus() { return KuraAlertStatus.valueOf((String) getMetric(STATUS_METRIC_NAME)); } public String getMessage() { final Object rawMessage = getMetric(MESSAGE_METRIC_NAME); if (rawMessage instanceof String) { return (String) rawMessage; } return null; } public Date getCreationTimestamp() { try { return DATE_FORMAT.parse((String) getMetric(CREATION_TIMESTAMP_METRIC_NAME)); } catch (Exception e) { return null; } } @Override public void addMetric(String name, Object value) { if (CODE_METRIC_NAME.equals(name)) { setCode((String) value); return; } else if (MESSAGE_METRIC_NAME.equals(name)) { setMessage((String) value); return; } else if (CREATION_TIMESTAMP_METRIC_NAME.equals(name)) { setCreationTimestamp((Date) value); return; } else if (SEVERITY_METRIC_NAME.equals(name)) { KuraAlertSeverity.valueOf((String) value); } else if (STATUS_METRIC_NAME.equals(name)) { KuraAlertStatus.valueOf((String) value); } super.addMetric(name, value); } private String validateCode(final String code) { final String trimmed = code.trim(); if (trimmed.isEmpty()) { throw new IllegalArgumentException("alert code cannot be empty"); } return trimmed; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertSeverity.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; /** * @since 2.0 */ public enum KuraAlertSeverity { WARNING, CRITICAL; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraAlertStatus.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; /** * @since 2.0 */ public enum KuraAlertStatus { ACTIVE, INACTIVE, RESET; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraApplicationTopic.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import org.osgi.annotation.versioning.ProviderType; /** * Models the application specific part of the topic for messages posted to the Kura platform. * * @noextend This class is not intended to be subclassed by clients. * @since 2.0 */ @ProviderType public abstract class KuraApplicationTopic { protected String applicationId; protected String applicationTopic; public String getApplicationId() { return this.applicationId; } public String getApplicationTopic() { return this.applicationTopic; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraBirthPayload.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import static org.eclipse.kura.message.KuraDeviceProfile.APPLICATION_FRAMEWORK_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.APPLICATION_FRAMEWORK_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.AVAILABLE_PROCESSORS_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.BIOS_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.CONNECTION_INTERFACE_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.CONNECTION_IP_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.CPU_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK; import static org.eclipse.kura.message.KuraDeviceProfile.DISPLAY_NAME_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.FIRMWARE_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.JDK_VENDOR_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.JVM_NAME_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.JVM_PROFILE_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.JVM_VENDOR_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.JVM_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.KURA_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.MODEL_ID_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.MODEL_NAME_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.OSGI_FRAMEWORK_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.OSGI_FRAMEWORK_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.OS_ARCH_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.OS_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.OS_VERSION_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.PART_NUMBER_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.SERIAL_NUMBER_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.TOTAL_MEMORY_KEY; import static org.eclipse.kura.message.KuraDeviceProfile.UPTIME_KEY; import java.util.Optional; /** * The KuraBirthPayload is an extension of {@link KuraPayload} that contains the parameters that allow to define the * form of a device. The message is usually published when connecting to the broker. * * @noextend This class is not intended to be subclassed by clients. * @since 2.1 */ public class KuraBirthPayload extends KuraPayload { /** * Provides information on the device tampering status. * * @since 2.2 */ public enum TamperStatus { /** * Tamper detection is not supported */ UNSUPPORTED, /** * The device has been tampered */ TAMPERED, /** * The device has not been tampered */ NOT_TAMPERED; } private static final String ACCEPT_ENCODING_KEY = "accept_encoding"; private static final String APPLICATION_IDS_KEY = "application_ids"; private static final String MODEM_IMEI_KEY = "modem_imei"; private static final String MODEM_IMSI_KEY = "modem_imsi"; private static final String MODEM_ICCID_KEY = "modem_iccid"; private static final String MODEM_RSSI_KEY = "modem_rssi"; private static final String MODEM_FIRMWARE_VERSION = "modem_firmware_version"; private static final String PAYLOAD_ENCODING_KEY = "payload_encoding"; /** * @since 2.2 */ private static final String TAMPER_STATUS = "tamper_status"; public String getUptime() { return (String) getMetric(UPTIME_KEY); } public String getDisplayName() { return (String) getMetric(DISPLAY_NAME_KEY); } public String getModelName() { return (String) getMetric(MODEL_NAME_KEY); } public String getModelId() { return (String) getMetric(MODEL_ID_KEY); } public String getPartNumber() { return (String) getMetric(PART_NUMBER_KEY); } public String getSerialNumber() { return (String) getMetric(SERIAL_NUMBER_KEY); } public String getFirmwareVersion() { return (String) getMetric(FIRMWARE_VERSION_KEY); } public String getBiosVersion() { return (String) getMetric(BIOS_VERSION_KEY); } /** * @since 2.2 */ public String getCpuVersion() { return (String) getMetric(CPU_VERSION_KEY); } public String getOs() { return (String) getMetric(OS_KEY); } public String getOsVersion() { return (String) getMetric(OS_VERSION_KEY); } public String getJvmName() { return (String) getMetric(JVM_NAME_KEY); } public String getJvmVersion() { return (String) getMetric(JVM_VERSION_KEY); } public String getJvmProfile() { return (String) getMetric(JVM_PROFILE_KEY); } /** * @since 2.2 */ public TamperStatus getTamperStatus() { final String tamperStatus = (String) getMetric(TAMPER_STATUS); if (tamperStatus == null) { return TamperStatus.UNSUPPORTED; } return TamperStatus.valueOf(tamperStatus); } /** * @deprecated Use {@link #getApplicationFrameworkVersion()} */ @Deprecated public String getKuraVersion() { return (String) getMetric(KURA_VERSION_KEY); } public String getApplicationFramework() { final String value = (String) getMetric(APPLICATION_FRAMEWORK_KEY); if (value != null) { return value; } return DEFAULT_APPLICATION_FRAMEWORK; } public String getApplicationFrameworkVersion() { final String value = (String) getMetric(APPLICATION_FRAMEWORK_VERSION_KEY); if (value != null) { return value; } return (String) getMetric(KURA_VERSION_KEY); } public String getConnectionInterface() { return (String) getMetric(CONNECTION_INTERFACE_KEY); } public String getConnectionIp() { return (String) getMetric(CONNECTION_IP_KEY); } public String getAcceptEncoding() { return (String) getMetric(ACCEPT_ENCODING_KEY); } public String getApplicationIdentifiers() { return (String) getMetric(APPLICATION_IDS_KEY); } public String getAvailableProcessors() { return (String) getMetric(AVAILABLE_PROCESSORS_KEY); } public String getTotalMemory() { return (String) getMetric(TOTAL_MEMORY_KEY); } public String getOsArch() { return (String) getMetric(OS_ARCH_KEY); } public String getOsgiFramework() { return (String) getMetric(OSGI_FRAMEWORK_KEY); } public String getOsgiFrameworkVersion() { return (String) getMetric(OSGI_FRAMEWORK_VERSION_KEY); } public String getModemImei() { return (String) getMetric(MODEM_IMEI_KEY); } public String getModemImsi() { return (String) getMetric(MODEM_IMSI_KEY); } public String getModemIccid() { return (String) getMetric(MODEM_ICCID_KEY); } public String getModemRssi() { return (String) getMetric(MODEM_RSSI_KEY); } /** * @since 2.2 */ public String getModemFirmwareVersion() { return (String) getMetric(MODEM_FIRMWARE_VERSION); } public String getPayloadEncoding() { return (String) getMetric(PAYLOAD_ENCODING_KEY); } /** * @since 2.6 */ public String getJvmVendor() { return (String) getMetric(JVM_VENDOR_KEY); } /** * @since 2.6 */ public String getJdkVendorVersion() { return (String) getMetric(JDK_VENDOR_VERSION_KEY); } @Override public String toString() { final StringBuilder sb = new StringBuilder("KuraBirthPayload ["); sb.append("getUptime()=").append(getUptime()).append(", "); sb.append("getDisplayName()=").append(getDisplayName()).append(", "); sb.append("getModelName()=").append(getModelName()).append(", "); sb.append("getModelId()=").append(getModelId()).append(", "); sb.append("getPartNumber()=").append(getPartNumber()).append(", "); sb.append("getSerialNumber()=").append(getSerialNumber()).append(", "); sb.append("getFirmwareVersion()=").append(getFirmwareVersion()).append(", "); sb.append("getAvailableProcessors()=").append(getAvailableProcessors()).append(", "); sb.append("getTotalMemory()=").append(getTotalMemory()).append(", "); sb.append("getBiosVersion()=").append(getBiosVersion()).append(", "); sb.append("getCpuVersion()=").append(getCpuVersion()).append(", "); sb.append("getOs()=").append(getOs()).append(", "); sb.append("getOsVersion()=").append(getOsVersion()).append(", "); sb.append("getOsArch()=").append(getOsArch()).append(", "); sb.append("getJvmName()=").append(getJvmName()).append(", "); sb.append("getJvmVersion()=").append(getJvmVersion()).append(", "); sb.append("getJvmProfile()=").append(getJvmProfile()).append(", "); sb.append("getKuraVersion()=").append(getApplicationFrameworkVersion()).append(", "); sb.append("getApplicationFramework()=").append(getApplicationFramework()).append(", "); sb.append("getApplicationFrameworkVersion()=").append(getApplicationFrameworkVersion()).append(", "); sb.append("getOsgiFramework()=").append(getOsgiFramework()).append(", "); sb.append("getOsgiFrameworkVersion()=").append(getOsgiFrameworkVersion()).append(", "); sb.append("getConnectionInterface()=").append(getConnectionInterface()).append(", "); sb.append("getConnectionIp()=").append(getConnectionIp()).append(", "); sb.append("getAcceptEncoding()=").append(getAcceptEncoding()).append(", "); sb.append("getApplicationIdentifiers()=").append(getApplicationIdentifiers()).append(", "); sb.append("getPayloadEncoding()=").append(getPayloadEncoding()).append(", "); sb.append("getTamperStatus()=").append(getTamperStatus()).append(", "); sb.append("getJvmVendor()=").append(getJvmVendor()).append(", "); sb.append("getJdkVendorVersion()=").append(getJdkVendorVersion()); sb.append("]"); return sb.toString(); } @Override public void addMetric(String name, Object value) { if (value != null) { super.addMetric(name, value); } } public static class KuraBirthPayloadBuilder { private String uptime; private String displayName; private String availableProcessors; private String totalMemory; private String osArch; private String modelName; private String modelId; private String partNumber; private String serialNumber; private String firmwareVersion; private String biosVersion; private String cpuVersion; private String os; private String osVersion; private String jvmName; private String jvmVersion; private String jvmProfile; private String jvmVendor; private Optional jdkVendorVersion; private String kuraVersion; private String applicationFramework; private String applicationFrameworkVersion; private String connectionInterface; private String connectionIp; private String acceptEncoding; private String applicationIdentifiers; private String osgiFramework; private String osgiFrameworkVersion; private String modemImei; private String modemIccid; private String modemImsi; private String modemRssi; private String modemFirmwareVersion; private String payloadEncoding; private TamperStatus tamperStatus; private KuraPosition position; public KuraBirthPayloadBuilder withUptime(String uptime) { this.uptime = uptime; return this; } public KuraBirthPayloadBuilder withDisplayName(String displayName) { this.displayName = displayName; return this; } public KuraBirthPayloadBuilder withAvailableProcessors(String availableProcessors) { this.availableProcessors = availableProcessors; return this; } public KuraBirthPayloadBuilder withTotalMemory(String totalMemory) { this.totalMemory = totalMemory; return this; } public KuraBirthPayloadBuilder withOsArch(String osArch) { this.osArch = osArch; return this; } public KuraBirthPayloadBuilder withOsgiFramework(String osgiFramework) { this.osgiFramework = osgiFramework; return this; } public KuraBirthPayloadBuilder withOsgiFrameworkVersion(String osgiFrameworkVersion) { this.osgiFrameworkVersion = osgiFrameworkVersion; return this; } public KuraBirthPayloadBuilder withModelName(String modelName) { this.modelName = modelName; return this; } public KuraBirthPayloadBuilder withModelId(String modelId) { this.modelId = modelId; return this; } public KuraBirthPayloadBuilder withPartNumber(String partNumber) { this.partNumber = partNumber; return this; } public KuraBirthPayloadBuilder withSerialNumber(String serialNumber) { this.serialNumber = serialNumber; return this; } public KuraBirthPayloadBuilder withFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; return this; } public KuraBirthPayloadBuilder withBiosVersion(String biosVersion) { this.biosVersion = biosVersion; return this; } /** * @since 2.2 */ public KuraBirthPayloadBuilder withCpuVersion(String cpuVersion) { this.cpuVersion = cpuVersion; return this; } public KuraBirthPayloadBuilder withOs(String os) { this.os = os; return this; } public KuraBirthPayloadBuilder withOsVersion(String osVersion) { this.osVersion = osVersion; return this; } public KuraBirthPayloadBuilder withJvmName(String jvmName) { this.jvmName = jvmName; return this; } public KuraBirthPayloadBuilder withJvmVersion(String jvmVersion) { this.jvmVersion = jvmVersion; return this; } public KuraBirthPayloadBuilder withJvmProfile(String jvmProfile) { this.jvmProfile = jvmProfile; return this; } public KuraBirthPayloadBuilder withKuraVersion(String kuraVersion) { withApplicationFramework(DEFAULT_APPLICATION_FRAMEWORK); withApplicationFrameworkVersion(kuraVersion); return this; } public KuraBirthPayloadBuilder withApplicationFramework(String applicationFramework) { this.applicationFramework = applicationFramework; return this; } public KuraBirthPayloadBuilder withApplicationFrameworkVersion(String applicationFrameworkVersion) { this.applicationFrameworkVersion = applicationFrameworkVersion; return this; } public KuraBirthPayloadBuilder withConnectionInterface(String connectionInterface) { this.connectionInterface = connectionInterface; return this; } public KuraBirthPayloadBuilder withConnectionIp(String connectionIp) { this.connectionIp = connectionIp; return this; } public KuraBirthPayloadBuilder withAcceptEncoding(String acceptEncoding) { this.acceptEncoding = acceptEncoding; return this; } public KuraBirthPayloadBuilder withApplicationIdentifiers(String applicationIdentifiers) { this.applicationIdentifiers = applicationIdentifiers; return this; } public KuraBirthPayloadBuilder withModemImei(String modemImei) { this.modemImei = modemImei; return this; } public KuraBirthPayloadBuilder withModemIccid(String modemIccid) { this.modemIccid = modemIccid; return this; } public KuraBirthPayloadBuilder withModemImsi(String modemImsi) { this.modemImsi = modemImsi; return this; } public KuraBirthPayloadBuilder withModemRssi(String modemRssi) { this.modemRssi = modemRssi; return this; } /** * @since 2.2 */ public KuraBirthPayloadBuilder withModemFirmwareVersion(String modemFirmwareVersion) { this.modemFirmwareVersion = modemFirmwareVersion; return this; } public KuraBirthPayloadBuilder withPosition(KuraPosition position) { this.position = position; return this; } public KuraBirthPayloadBuilder withPayloadEncoding(String payloadEncoding) { this.payloadEncoding = payloadEncoding; return this; } /** * @since 2.2 */ public KuraBirthPayloadBuilder withTamperStatus(TamperStatus tamperStatus) { this.tamperStatus = tamperStatus; return this; } /** * * @since 2.6 * @param jvmVendor * @return */ public KuraBirthPayloadBuilder withJvmVendor(String jvmVendor) { this.jvmVendor = jvmVendor; return this; } /** * * @since 2.6 * @param jdkVendorVersion * @return */ public KuraBirthPayloadBuilder withJdkVendorVersion(String jdkVendorVersion) { this.jdkVendorVersion = Optional.ofNullable(jdkVendorVersion); return this; } public KuraBirthPayload build() { KuraBirthPayload birthPayload = new KuraBirthPayload(); birthPayload.addMetric(UPTIME_KEY, this.uptime); birthPayload.addMetric(DISPLAY_NAME_KEY, this.displayName); birthPayload.addMetric(MODEL_NAME_KEY, this.modelName); birthPayload.addMetric(MODEL_ID_KEY, this.modelId); birthPayload.addMetric(PART_NUMBER_KEY, this.partNumber); birthPayload.addMetric(SERIAL_NUMBER_KEY, this.serialNumber); birthPayload.addMetric(FIRMWARE_VERSION_KEY, this.firmwareVersion); birthPayload.addMetric(BIOS_VERSION_KEY, this.biosVersion); birthPayload.addMetric(CPU_VERSION_KEY, this.cpuVersion); birthPayload.addMetric(OS_KEY, this.os); birthPayload.addMetric(OS_VERSION_KEY, this.osVersion); birthPayload.addMetric(JVM_NAME_KEY, this.jvmName); birthPayload.addMetric(JVM_VERSION_KEY, this.jvmVersion); birthPayload.addMetric(JVM_PROFILE_KEY, this.jvmProfile); birthPayload.addMetric(KURA_VERSION_KEY, this.kuraVersion); if (this.applicationFramework != null) { birthPayload.addMetric(APPLICATION_FRAMEWORK_KEY, this.applicationFramework); } else { birthPayload.addMetric(APPLICATION_FRAMEWORK_KEY, DEFAULT_APPLICATION_FRAMEWORK); } birthPayload.addMetric(KURA_VERSION_KEY, this.applicationFrameworkVersion); birthPayload.addMetric(APPLICATION_FRAMEWORK_VERSION_KEY, this.applicationFrameworkVersion); birthPayload.addMetric(CONNECTION_INTERFACE_KEY, this.connectionInterface); birthPayload.addMetric(CONNECTION_IP_KEY, this.connectionIp); birthPayload.addMetric(ACCEPT_ENCODING_KEY, this.acceptEncoding); birthPayload.addMetric(APPLICATION_IDS_KEY, this.applicationIdentifiers); birthPayload.addMetric(AVAILABLE_PROCESSORS_KEY, this.availableProcessors); birthPayload.addMetric(TOTAL_MEMORY_KEY, this.totalMemory); birthPayload.addMetric(OS_ARCH_KEY, this.osArch); birthPayload.addMetric(OSGI_FRAMEWORK_KEY, this.osgiFramework); birthPayload.addMetric(OSGI_FRAMEWORK_VERSION_KEY, this.osgiFrameworkVersion); birthPayload.addMetric(MODEM_IMEI_KEY, this.modemImei); birthPayload.addMetric(MODEM_ICCID_KEY, this.modemIccid); birthPayload.addMetric(MODEM_IMSI_KEY, this.modemImsi); birthPayload.addMetric(MODEM_RSSI_KEY, this.modemRssi); birthPayload.addMetric(MODEM_FIRMWARE_VERSION, this.modemFirmwareVersion); birthPayload.addMetric(PAYLOAD_ENCODING_KEY, this.payloadEncoding); if (tamperStatus != null && tamperStatus != TamperStatus.UNSUPPORTED) { birthPayload.addMetric(TAMPER_STATUS, tamperStatus.name()); } birthPayload.setPosition(this.position); birthPayload.addMetric(JVM_VENDOR_KEY, this.jvmVendor); if (this.jdkVendorVersion.isPresent()) { birthPayload.addMetric(JDK_VENDOR_VERSION_KEY, this.jdkVendorVersion.get()); } return birthPayload; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraDeviceProfile.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; /** * The KuraDeviceProfile is a container class that holds the parameters that make up the from of a device. * This information is used to build the birth and disconnect certificates that are published when * connecting to and disconnecting from the broker. * * @noextend This class is not intended to be subclassed by clients. * @since 2.1 * */ public class KuraDeviceProfile { public static final String UPTIME_KEY = "uptime"; public static final String DISPLAY_NAME_KEY = "display_name"; public static final String MODEL_NAME_KEY = "model_name"; public static final String MODEL_ID_KEY = "model_id"; public static final String PART_NUMBER_KEY = "part_number"; public static final String SERIAL_NUMBER_KEY = "serial_number"; public static final String AVAILABLE_PROCESSORS_KEY = "available_processors"; public static final String TOTAL_MEMORY_KEY = "total_memory"; public static final String FIRMWARE_VERSION_KEY = "firmware_version"; /** * @since 2.2 */ public static final String CPU_VERSION_KEY = "cpu_version"; public static final String BIOS_VERSION_KEY = "bios_version"; public static final String OS_KEY = "os"; public static final String OS_VERSION_KEY = "os_version"; public static final String OS_ARCH_KEY = "os_arch"; public static final String JVM_NAME_KEY = "jvm_name"; public static final String JVM_VERSION_KEY = "jvm_version"; public static final String JVM_PROFILE_KEY = "jvm_profile"; public static final String KURA_VERSION_KEY = "kura_version"; public static final String APPLICATION_FRAMEWORK_KEY = "application_framework"; public static final String APPLICATION_FRAMEWORK_VERSION_KEY = "application_framework_version"; public static final String OSGI_FRAMEWORK_KEY = "osgi_framework"; public static final String OSGI_FRAMEWORK_VERSION_KEY = "osgi_framework_version"; public static final String CONNECTION_INTERFACE_KEY = "connection_interface"; public static final String CONNECTION_IP_KEY = "connection_ip"; public static final String DEFAULT_APPLICATION_FRAMEWORK = "Kura"; /** * @since 2.6 */ public static final String JVM_VENDOR_KEY = "jvm_vendor"; /** * @since 2.6 */ public static final String JDK_VENDOR_VERSION_KEY = "jdk_vendor_version"; private String uptime; private String displayName; private String modelName; private String modelId; private String partNumber; private String serialNumber; private String availableProcessors; private String totalMemory; private String firmwareVersion; private String biosVersion; private String cpuVersion; private String os; private String osVersion; private String osArch; private String jvmName; private String jvmVersion; private String jvmProfile; private String applicationFramework; private String applicationFrameworkVersion; private String osgiFramework; private String osgiFrameworkVersion; private String connectionInterface; private String connectionIp; private Double latitude; private Double longitude; private Double altitude; private String jvmVendor; private String jdkVendorVersion; /** * Empty constructor for a KuraDeviceProfile. */ public KuraDeviceProfile() { // Values filled with setters } /** * Returns The length of time the unit has been powered on. * * @return A String representing the length of time the device has been powered on. */ public String getUptime() { return this.uptime; } /** * Returns the readable display name for the device. * * @return A String representing the readable display name for the device. */ public String getDisplayName() { return this.displayName; } /** * Returns the device model name * * @return A String representing the device model name */ public String getModelName() { return this.modelName; } /** * Returns the device model ID. * * @return A String representing the device model ID. */ public String getModelId() { return this.modelId; } /** * Returns the part number of the device. * * @return A String representing the part number of the device. */ public String getPartNumber() { return this.partNumber; } /** * Returns the serial number of the device. * * @return A String representing the serial number of the device. */ public String getSerialNumber() { return this.serialNumber; } /** * Returns the version of firmware running on the device. * * @return A String representing the version of firmware running on the device. */ public String getFirmwareVersion() { return this.firmwareVersion; } /** * Returns the version of the BIOS on the device. * * @return A String representing the version of the BIOS on the device. */ public String getBiosVersion() { return this.biosVersion; } /** * Returns the CPU version information. * * @since 2.2 * @return A string representing the CPU version information. */ public String getCpuVersion() { return this.cpuVersion; } /** * Returns the name of the operating system. * * @return A String representing the name of the operating system. */ public String getOs() { return this.os; } /** * Returns the version of the operating system. * * @return A String representing the version of the operating system. */ public String getOsVersion() { return this.osVersion; } /** * Returns the name of the JVM. * * @return A String representing the name of the JVM. */ public String getJvmName() { return this.jvmName; } /** * Returns the version of the JVM. * * @return A String representing the version of the JVM. */ public String getJvmVersion() { return this.jvmVersion; } /** * Returns the profile of the JVM. * * @return A String representing the profile of the JVM. */ public String getJvmProfile() { return this.jvmProfile; } /** * Returns the Kura version. * * @return A String representing the Kura version * @deprecated use {@link #getApplicationFrameworkVersion()} instead */ @Deprecated public String getKuraVersion() { return this.applicationFrameworkVersion; } /** * Returns the Application Framework. * * @return A String representing the Application Framework */ public String getApplicationFramework() { return this.applicationFramework; } /** * Returns the Application Framework version. * * @return A String representing the Application Framework version */ public String getApplicationFrameworkVersion() { return this.applicationFrameworkVersion; } /** * Returns the name of the interface used to connect to the cloud. * * @return A String representing the name of the interface used to connect to the cloud. */ public String getConnectionInterface() { return this.connectionInterface; } /** * Returns the IP address of the interface used to connect to the cloud. * * @return A String representing the IP address of the interface used to connect to the cloud. */ public String getConnectionIp() { return this.connectionIp; } /** * Returns the latitude of the device's location. * * @return A String representing the latitude of the device's location. */ public Double getLatitude() { return this.latitude; } /** * Returns the longitude of the device's location. * * @return A String representing the longitude of the device's location. */ public Double getLongitude() { return this.longitude; } /** * Returns the altitude of the device's location. * * @return A String representing thealtitude of the device's location. */ public Double getAltitude() { return this.altitude; } /** * * @since 2.6 * @return a String representing the JVM vendor name. */ public String getJvmVendor() { return this.jvmVendor; } /** * * @since 2.6 * @return a String representing the JDK vendor version. */ public String getJdkVendorVersion() { return this.jdkVendorVersion; } /** * Sets the length of time the unit has been powered on. * * @param uptime * A String representing the length of time the unit has been powered on. */ public void setUptime(String uptime) { this.uptime = uptime; } /** * Sets the readable display name for the device * * @param displayName * A String representing the readable display name for the device */ public void setDisplayName(String displayName) { this.displayName = displayName; } /** * Sets the device model name. * * @param modelName * A String representing the device model name. */ public void setModelName(String modelName) { this.modelName = modelName; } /** * Sets the device model ID. * * @param modelId * A String representing the device model ID. */ public void setModelId(String modelId) { this.modelId = modelId; } /** * Sets the part number of the device. * * @param partNumber * A String representing the part number of the device. */ public void setPartNumber(String partNumber) { this.partNumber = partNumber; } /** * Sets the serial number of the device. * * @param serialNumber * A String representing the serial number of the device. */ public void setSerialNumber(String serialNumber) { this.serialNumber = serialNumber; } /** * Sets the version of firmware running on the device. * * @param firmwareVersion * A String representing the version of firmware running on the device. */ public void setFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; } /** * Sets the version of the BIOS on the device. * * @param biosVersion * A String representing the version of the BIOS on the device. */ public void setBiosVersion(String biosVersion) { this.biosVersion = biosVersion; } /** * Sets the CPU version information * * @since 2.2 * @param cpuVersion * the CPU version information */ public void setCpuVersion(String cpuVersion) { this.cpuVersion = cpuVersion; } /** * Sets the name of the operating system. * * @param os * A String representing the name of the operating system. */ public void setOs(String os) { this.os = os; } /** * Sets the version of the operating system. * * @param osVersion * A String representing the version of the operating system. */ public void setOsVersion(String osVersion) { this.osVersion = osVersion; } /** * Sets the name of the JVM. * * @param jvmName * A String representing the name of the JVM. */ public void setJvmName(String jvmName) { this.jvmName = jvmName; } /** * Sets the version of the JVM. * * @param jvmVersion * A String representing the version of the JVM. */ public void setJvmVersion(String jvmVersion) { this.jvmVersion = jvmVersion; } /** * Sets the profile of the JVM. * * @param jvmProfile * A String representing the profile of the JVM. */ public void setJvmProfile(String jvmProfile) { this.jvmProfile = jvmProfile; } /** * Sets the name of the interface used to connect to the cloud. * * @param connectionInterface * A String representing the name of the interface used to connect to the cloud. */ public void setConnectionInterface(String connectionInterface) { this.connectionInterface = connectionInterface; } /** * Sets the IP address of the interface used to connect to the cloud. * * @param connectionIp * A String representing the IP address of the interface used to connect to the cloud. */ public void setConnectionIp(String connectionIp) { this.connectionIp = connectionIp; } /** * Sets the latitude of the device's location. * * @param latitude * A String representing the latitude of the device's location. */ public void setLatitude(Double latitude) { this.latitude = latitude; } /** * Sets the longitude of the device's location. * * @param longitude * A String representing the longitude of the device's location. */ public void setLongitude(Double longitude) { this.longitude = longitude; } /** * Sets the altitude of the device's location. * * @param altitude * A String representing the altitude of the device's location. */ public void setAltitude(Double altitude) { this.altitude = altitude; } /** * * @since 2.6 * @param jvmVendor a String representing the JVM vendor name. */ public void setJvmVendor(String jvmVendor) { this.jvmVendor = jvmVendor; } /** * * @since 2.6 * @param jdkVendorVersion a String representing the JDK vendor version. */ public void setJdkVendorVersion(String jdkVendorVersion) { this.jdkVendorVersion = jdkVendorVersion; } public String getAvailableProcessors() { return this.availableProcessors; } public void setAvailableProcessors(String availableProcessors) { this.availableProcessors = availableProcessors; } public void setApplicationFramework(String applicationFramework) { this.applicationFramework = applicationFramework; } public void setApplicationFrameworkVersion(String applicationFrameworkVersion) { this.applicationFrameworkVersion = applicationFrameworkVersion; } public String getTotalMemory() { return this.totalMemory; } public void setTotalMemory(String totalMemory) { this.totalMemory = totalMemory; } public String getOsArch() { return this.osArch; } public void setOsArch(String osArch) { this.osArch = osArch; } public String getOsgiFramework() { return this.osgiFramework; } public void setOsgiFramework(String osgiFramework) { this.osgiFramework = osgiFramework; } public String getOsgiFrameworkVersion() { return this.osgiFrameworkVersion; } public void setOsgiFrameworkVersion(String osgiFrameworkVersion) { this.osgiFrameworkVersion = osgiFrameworkVersion; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraDisconnectPayload.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.util.Iterator; /** * The KuraDisconnectPayload is an extension of {@link KuraPayload} that contains the parameters stored in a message * that is usually published when disconnecting from the broker. * * @noextend This class is not intended to be subclassed by clients. * @since 2.1 */ public class KuraDisconnectPayload extends KuraPayload { private static final String UPTIME = "uptime"; private static final String DISPLAY_NAME = "display_name"; public KuraDisconnectPayload(String uptime, String displayName) { super(); addMetric(UPTIME, uptime); addMetric(DISPLAY_NAME, displayName); } public KuraDisconnectPayload(KuraPayload kuraMessage) { Iterator hdrIterator = kuraMessage.metricsIterator(); while (hdrIterator.hasNext()) { String hdrName = hdrIterator.next(); String hdrVal = (String) kuraMessage.getMetric(hdrName); addMetric(hdrName, hdrVal); } setBody(kuraMessage.getBody()); } public String getUptime() { return (String) getMetric(UPTIME); } public String getDisplayName() { return (String) getMetric(DISPLAY_NAME); } @Override public String toString() { return "KuraBirthMessage [getUptime()=" + getUptime() + ", getDisplayName()=" + getDisplayName() + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraPayload.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; /** * KuraPayload defines the recommended payload structure for the messages sent to a remote cloud platform. * It was defined as an open format that is flexible from the aspect of data modeling * yet is efficient when it comes to bandwidth conservation. The same payload model could be used by the REST API * - in which case it is serialized into XML or JSON as requested by the client - or uses the efficient * Google ProtoBuf when sent over an MQTT connection when the bandwidth is very important. * The KuraPayload contains the following fields: sentOn timestamp, an optional set of metrics represented as * name-value pairs, an optional position field to capture a GPS position, and an optional binary body. *
    *
  • sentOn: it is the timestamp when the data was captured and sent to the remote cloud platform. *
  • metrics: a metric is a data structure composed of the name, a value, and the type of the value. * When used with the REST API valid metric types are: string, double, int, float, long, boolean, base64Binary. * * Each payload can have zero or more metrics. *
  • position: it is an optional field used to capture a geo position associated to this payload. *
  • body: it is an optional part of the payload that allows additional information to be transmitted in any format * determined by the user. *
* * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraPayload { /** * Timestamp when the data was captured and sent to the remote cloud platform. */ private Date timestamp; /** * It is an optional field used to capture a geo position associated to this payload. */ private KuraPosition position; /** * A metric is a data structure composed of the name, a value, and the type of the value. * When used with the REST API valid metric types are: string, double, int, float, long, boolean, base64Binary. * Each payload can have zero or more metrics. */ private final Map metrics; /** * It is an optional part of the payload that allows additional information to be transmitted in any format * determined by the user. */ private byte[] body; public KuraPayload() { this.metrics = new HashMap<>(); this.body = null; } public Date getTimestamp() { return this.timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public KuraPosition getPosition() { return this.position; } public void setPosition(KuraPosition position) { this.position = position; } public Object getMetric(String name) { return this.metrics.get(name); } public void addMetric(String name, Object value) { this.metrics.put(name, value); } public void removeMetric(String name) { this.metrics.remove(name); } public void removeAllMetrics() { this.metrics.clear(); } public Set metricNames() { return Collections.unmodifiableSet(this.metrics.keySet()); } public Iterator metricsIterator() { return this.metrics.keySet().iterator(); } public Map metrics() { return Collections.unmodifiableMap(this.metrics); } public byte[] getBody() { return this.body; } public void setBody(byte[] body) { this.body = body; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraPosition.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.util.Date; import org.osgi.annotation.versioning.ProviderType; /** * KuraPosition is a data structure to capture a geo location. It can be * associated to a KuraPayload to geotag a KuraMessage before sending to a * remote cloud platform. Refer to the description of each of the fields for more * information on the model of KuraPosition. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraPosition { /** * Longitude of this position in degrees. This is a mandatory field. */ private Double longitude; /** * Latitude of this position in degrees. This is a mandatory field. */ private Double latitude; /** * Altitude of the position in meters. */ private Double altitude; /** * Dilution of the precision (DOP) of the current GPS fix. */ private Double precision; /** * Heading (direction) of the position in degrees */ private Double heading; /** * Speed for this position in meter/sec. */ private Double speed; /** * Timestamp extracted from the GPS system */ private Date timestamp; /** * Number of satellites seen by the systems */ private Integer satellites; /** * Status of GPS system: 1 = no GPS response, 2 = error in response, 4 = * valid. */ private Integer status; public KuraPosition() { } public Double getLongitude() { return this.longitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public Double getLatitude() { return this.latitude; } public void setLatitude(double latitude) { this.latitude = latitude; } public Double getAltitude() { return this.altitude; } public void setAltitude(double altitude) { this.altitude = altitude; } public Double getPrecision() { return this.precision; } public void setPrecision(double precision) { this.precision = precision; } public Double getHeading() { return this.heading; } public void setHeading(double heading) { this.heading = heading; } public Double getSpeed() { return this.speed; } public void setSpeed(double speed) { this.speed = speed; } public Date getTimestamp() { return this.timestamp; } public void setTimestamp(Date timestamp) { this.timestamp = timestamp; } public Integer getSatellites() { return this.satellites; } public void setSatellites(int satellites) { this.satellites = satellites; } public Integer getStatus() { return this.status; } public void setStatus(int status) { this.status = status; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraRequestPayload.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.text.ParseException; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraRequestPayload extends KuraPayload { public static final String METRIC_REQUEST_ID = "request.id"; public static final String REQUESTER_CLIENT_ID = "requester.client.id"; public KuraRequestPayload() { super(); } public KuraRequestPayload(KuraPayload payload) { super(); for (String name : payload.metricNames()) { Object value = payload.getMetric(name); addMetric(name, value); } setBody(payload.getBody()); setPosition(payload.getPosition()); setTimestamp(payload.getTimestamp()); } public String getRequestId() { return (String) getMetric(METRIC_REQUEST_ID); } public void setRequestId(String requestId) { addMetric(METRIC_REQUEST_ID, requestId); } public String getRequesterClientId() { return (String) getMetric(REQUESTER_CLIENT_ID); } public void setRequesterClientId(String requesterClientId) { addMetric(REQUESTER_CLIENT_ID, requesterClientId); } public static KuraRequestPayload buildFromKuraPayload(KuraPayload payload) throws ParseException { if (payload.getMetric(METRIC_REQUEST_ID) == null) { throw new ParseException("Not a valid request payload", 0); } KuraRequestPayload requestPayload = new KuraRequestPayload(payload); return requestPayload; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraResponsePayload.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import java.io.PrintWriter; import java.io.StringWriter; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class KuraResponsePayload extends KuraPayload { public static final int RESPONSE_CODE_OK = 200; public static final int RESPONSE_CODE_BAD_REQUEST = 400; public static final int RESPONSE_CODE_NOTFOUND = 404; public static final int RESPONSE_CODE_ERROR = 500; public static final String METRIC_RESPONSE_CODE = "response.code"; public static final String METRIC_EXCEPTION_MSG = "response.exception.message"; public static final String METRIC_EXCEPTION_STACK = "response.exception.stack"; public KuraResponsePayload(int responseCode) { super(); addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode)); } public KuraResponsePayload(Throwable t) { this(RESPONSE_CODE_ERROR, t); } public KuraResponsePayload(int responseCode, Throwable t) { super(); addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode)); setException(t); } public KuraResponsePayload(KuraPayload kuraPayload) { for (String name : kuraPayload.metricNames()) { Object value = kuraPayload.getMetric(name); addMetric(name, value); } setBody(kuraPayload.getBody()); } public int getResponseCode() { return (Integer) getMetric(METRIC_RESPONSE_CODE); } public void setResponseCode(int responseCode) { addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode)); } public String getExceptionMessage() { return (String) getMetric(METRIC_EXCEPTION_MSG); } public void setExceptionMessage(String message) { if (message != null) { addMetric(METRIC_EXCEPTION_MSG, message); } } public String getExceptionStack() { return (String) getMetric(METRIC_EXCEPTION_STACK); } public void setExceptionStack(String stack) { if (stack != null) { addMetric(METRIC_EXCEPTION_STACK, stack); } } public void setException(Throwable t) { if (t != null) { addMetric(METRIC_EXCEPTION_MSG, t.getMessage()); addMetric(METRIC_EXCEPTION_STACK, stackTraceAsString(t)); } } private String stackTraceAsString(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/KuraTopic.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message; import org.osgi.annotation.versioning.ProviderType; /** * Models a topic for messages posted to the Kura platform. * Topics are expected to be in the form of "account/asset/<application_specific>"; * The system control topic prefix is defined in the {@link org.eclipse.kura.cloud.CloudService} and defaults * to $EDC. * * @noextend This class is not intended to be subclassed by clients. * @deprecated Please use the new Cloud Connection APIs and refer to {@link KuraApplicationTopic} */ @Deprecated @ProviderType public class KuraTopic { private String fullTopic; private String[] topicParts; private String prefix; private String accountName; private String deviceId; private String applicationId; private String applicationTopic; public KuraTopic(String fullTopic) { this(fullTopic, "$"); } public KuraTopic(String fullTopic, String controlPrefix) { this.fullTopic = fullTopic; if (fullTopic.compareTo("#") == 0) { return; } this.topicParts = fullTopic.split("/"); if (this.topicParts.length == 0) { return; } // prefix int index = 0; int offset = 0; // skip a slash if (this.topicParts[0].startsWith(controlPrefix)) { this.prefix = this.topicParts[index]; offset += this.prefix.length() + 1; index++; } // account name if (index < this.topicParts.length) { this.accountName = this.topicParts[index]; offset += this.accountName.length() + 1; index++; } // deviceId if (index < this.topicParts.length) { this.deviceId = this.topicParts[index]; offset += this.deviceId.length() + 1; index++; } // applicationId if (index < this.topicParts.length) { this.applicationId = this.topicParts[index]; offset += this.applicationId.length() + 1; index++; } // applicationTopic if (offset < this.fullTopic.length()) { this.applicationTopic = this.fullTopic.substring(offset); } } public String getFullTopic() { return this.fullTopic; } public String[] getTopicParts() { return this.topicParts; } public String getPrefix() { return this.prefix; } public String getAccountName() { return this.accountName; } public String getDeviceId() { return this.deviceId; } public String getApplicationId() { return this.applicationId; } public String getApplicationTopic() { return this.applicationTopic; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Defines the recommended payload structure for the messages sent a remote cloud platform. * */ package org.eclipse.kura.message; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/StoredMessage.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message.store; import java.util.Arrays; import java.util.Date; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.data.DataTransportToken; import org.osgi.annotation.versioning.ProviderType; /** * Represents a message stored by a MessageStore implementation. * * @since 2.5 * @noextend This class is not intended to be extended by clients. */ @ProviderType public class StoredMessage { private final int id; private final String topic; private final int qos; private final boolean retain; private final int priority; private final byte[] payload; private final Optional createdOn; private final Optional publishedOn; private final Optional confirmedOn; private final Optional droppedOn; private final Optional dataTransportToken; private StoredMessage(final Builder b) { this.id = b.id; this.topic = b.topic; this.qos = b.qos; this.retain = b.retain; this.priority = b.priority; this.payload = b.payload; this.createdOn = Optional.ofNullable(b.createdOn); this.publishedOn = Optional.ofNullable(b.publishedOn); this.confirmedOn = Optional.ofNullable(b.confirmedOn); this.dataTransportToken = Optional.ofNullable(b.dataTransportToken); this.droppedOn = Optional.ofNullable(b.droppedOn); } /** * Returns the unique identifier of this message. * * @return the unique identifier of this message. */ public int getId() { return id; } /** * Returns the topic of this message. * * @return the topic. */ public String getTopic() { return topic; } /** * Returns the QoS of this message. * A QoS value of zero indicates that the message reception does not need to be * acknowledged by the recipient. * A QoS value greater or equal than one indicates that the acknowledgement is * required. * * @see StoredMessage#getConfirmedOn() * @return the QoS value */ public int getQos() { return qos; } /** * Returns the value of the MQTT retain field. * * @return the value of the MQTT retain. */ public boolean isRetain() { return retain; } /** * Defines a message priority. The lower the value of this field, the higher the * priority. *
* Messages with higher priority (lower value of this field) will be published * first. * * @return the priority value */ public int getPriority() { return priority; } /** * Returns the message payload. * * @return the message payload. */ public byte[] getPayload() { return payload; } /** * Returns the timestamp of the instant when this message has been added to a * store. * * @return the timestamp of creation instant */ public Optional getCreatedOn() { return createdOn; } /** * Returns the timestamp of the instant when this message has been sent to the * recipient. * An empty value means that the message has not been sent yet. * * @return the publish timestamp, if any. */ public Optional getPublishedOn() { return publishedOn; } /** * For messages with QoS greater or equal than one, this field reports the * timestamp of the instant when the confirmation has been received from the * recipient. *
* The returned value will be emtpy for messages with QoS zero, or for messages * with QoS * greater or equal than one that have not been confirmed yet. * * @see StoredMessage#getQos() * @return the timestamp of the confirmation, if any */ public Optional getConfirmedOn() { return confirmedOn; } /** * Returns the timestamp of the instant when this messages has been discarded. * If returned value is empty, this message has not been dropped. * * @return the discard timestamp, if any */ public Optional getDroppedOn() { return droppedOn; } /** * Returns the {@link DataTransportToken} associated with this message, if any. * A {@link DataTransportToken} is an identifier of this message * generated by the {@link org.eclipse.kura.data.DataTransportService} instance * that published it. * * @return the {@link DataTransportToken}. */ public Optional getDataTransportToken() { return dataTransportToken; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(payload); result = prime * result + Objects.hash(confirmedOn, createdOn, dataTransportToken, droppedOn, id, priority, publishedOn, qos, retain, topic); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof StoredMessage)) { return false; } StoredMessage other = (StoredMessage) obj; return Objects.equals(confirmedOn, other.confirmedOn) && Objects.equals(createdOn, other.createdOn) && Objects.equals(dataTransportToken, other.dataTransportToken) && Objects.equals(droppedOn, other.droppedOn) && id == other.id && Arrays.equals(payload, other.payload) && priority == other.priority && Objects.equals(publishedOn, other.publishedOn) && qos == other.qos && retain == other.retain && Objects.equals(topic, other.topic); } @Override public String toString() { return "StoredMessage [id=" + id + ", topic=" + topic + ", qos=" + qos + ", retain=" + retain + ", priority=" + priority + ", payload=" + Arrays.toString(payload) + ", createdOn=" + createdOn + ", publishedOn=" + publishedOn + ", confirmedOn=" + confirmedOn + ", droppedOn=" + droppedOn + ", dataTransportToken=" + dataTransportToken + "]"; } /** * A builder that can be used to create {@link StoredMessage} instances. * * @since 2.5 * @noextend This class is not intended to be extended by clients. */ @ProviderType public static class Builder { private final int id; private String topic; private int qos; private boolean retain; private byte[] payload; private int priority; private Date createdOn; private Date publishedOn; private Date confirmedOn; private Date droppedOn; private DataTransportToken dataTransportToken; /** * Creates a new builder for a message with the given id. * * @param id the message id. */ public Builder(int id) { this.id = id; } /** * Sets the topic parameter. * * @param topic the topic parameter. * @return this builder. */ public Builder withTopic(String topic) { this.topic = topic; return this; } /** * Sets the QoS parameter. * * @param qos the QoS parameter. * @return this builder. */ public Builder withQos(int qos) { this.qos = qos; return this; } /** * Sets the retain parameter. * * @param retain the retain parameter. * @return this builder. */ public Builder withRetain(boolean retain) { this.retain = retain; return this; } /** * Sets the createdOn parameter. * * @param createdOn the createdOn parameter. * @return this builder. */ public Builder withCreatedOn(Date createdOn) { this.createdOn = createdOn; return this; } /** * Sets the publishedOn parameter. * * @param publishedOn the publishedOn parameter. * @return this builder. */ public Builder withPublishedOn(Date publishedOn) { this.publishedOn = publishedOn; return this; } /** * Sets the confirmedOn parameter. * * @param confirmedOn the confirmedOn parameter. * @return this builder. */ public Builder withConfirmedOn(Date confirmedOn) { this.confirmedOn = confirmedOn; return this; } /** * Sets the payload parameter. * * @param payload the payload parameter. * @return this builder. */ public Builder withPayload(byte[] payload) { this.payload = payload; return this; } /** * Sets the priority parameter. * * @param priority the priority parameter. * @return this builder. */ public Builder withPriority(int priority) { this.priority = priority; return this; } /** * Sets the token parameter. * * @param token the token parameter. * @return this builder. */ public Builder withDataTransportToken(DataTransportToken token) { this.dataTransportToken = token; return this; } /** * Sets the droppedOn parameter. * * @param droppedOn the droppedOn parameter. * @return this builder. */ public Builder withDroppedOn(Date droppedOn) { this.droppedOn = droppedOn; return this; } /** * Created a new {@link StoredMessage} basing on this builder. * * @return the new message. */ public StoredMessage build() { return new StoredMessage(this); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides a representation of the messages stored by a * {@link org.eclipse.kura.message.store.provider.MessageStoreProvider} * instance. * * @since 2.5 */ package org.eclipse.kura.message.store; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/MessageStore.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message.store.provider; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.data.DataTransportToken; import org.eclipse.kura.message.store.StoredMessage; import org.osgi.annotation.versioning.ProviderType; /** * Represents a message store suitable for supporting the Kura default * {@link org.eclipse.kura.data.DataService} implementation. * * See {@link StoredMessage} for a description of the stored message fields. * * @since 2.5 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface MessageStore { /** * Inserts a new message in the store. The implementation must set the value of * the createdOn message parameter to the current time. *
* * @param topic the value of the topic parameter. * @param payload topic the value of the payload parameter. * @param qos topic the value of the QoS parameter. * @param retain topic the value of the retain parameter. * @param priority topic the value of the priority parameter. * @return An identifier for the stored message. * @throws KuraStoreException */ public int store(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException; /** * Sets the value of the publishedOn parameter to the current time. *
* This method must be used for messages with QoS = 0. * * @param msgId the message identifier * @throws KuraStoreException */ public void markAsPublished(int msgId) throws KuraStoreException; /** * Sets the value of the publishedOn parameter to the current time * and associates the given {@link DataTransportToken} with the current * message. *
* This method must be used for messages with QoS >= 1. * * @param msgId the message identifier. * @param dataTransportToken the {@link DataTransportToken}. * @throws KuraStoreException */ public void markAsPublished(int msgId, DataTransportToken dataTransportToken) throws KuraStoreException; /** * Sets the value of the confirmedOn parameter to the current time. *
* This method must be used for messages with QoS >= 1. * * @param msgId the message identifier. * @throws KuraStoreException */ public void markAsConfirmed(int msgId) throws KuraStoreException; /** * Gets the next message that should be published, if any. * * The returned message must have the following properties: * *
    *
  1. The publishedOn parameter must not be set.
  2. *
  3. It must have the lowest value of the priority numeric * parameter (highest priority) between messages that satisfy 1.
  4. *
  5. It must have the minimum createdOn parameter value between * the messages that satisfy 2.
  6. *
* * In other words it must be the oldest message between the ones with highest * priority that have not been published yet. * * @return the next message that should be published, if any. * @throws KuraStoreException */ public Optional getNextMessage() throws KuraStoreException; /** * Retrieves the message with the given identifier from the store. * * @param msgId the message identifier. * @return the retrieved message, or empty if there is no message in the store * with the given identifier. * @throws KuraStoreException */ public Optional get(int msgId) throws KuraStoreException; /** * Returns the number of messages currently in the store. * This should include all messages, regardless of the value of their * parameters. * * @return the message count. * @throws KuraStoreException */ public int getMessageCount() throws KuraStoreException; /** * Returns the list of messages whose publishedOn parameter is not * set. *
* It is not necessary to return the message payload. * * @return the unpublished message list. * @throws KuraStoreException */ public List getUnpublishedMessages() throws KuraStoreException; /** * Returns the list of messages that satisfy all of the following conditions: * *
    *
  1. The value of the QoS parameter is greater than 0.
  2. *
  3. The publishedOn parameter is set.
  4. *
  5. The confirmedOn parameter is not set.
  6. *
  7. The droppedOn parameter is not set.
  8. *
* * It is not necessary to return the message payload. * * @return the in-flight message list. * @throws KuraStoreException */ public List getInFlightMessages() throws KuraStoreException; /** * Returns the list of messages with the following property: * *
    *
  1. The droppedOn parameter must be set.
  2. *
* * It is not necessary to return the message payload. * * @return the dropped message list. * @throws KuraStoreException */ public List getDroppedMessages() throws KuraStoreException; /** * Removes the value of the publishedOn parameter from the messages * that satisfy all of the following conditions: * *
    *
  • The publishedOn parameter is set.
  • *
  • The confirmedOn parameter is not set.
  • *
* * @throws KuraStoreException */ public void unpublishAllInFlighMessages() throws KuraStoreException; /** * Sets the value of the droppedOn parameter to the current * timestamp to all messages that satisfy all of the following conditions: * *
    *
  • The value of the QoS parameter is greater than 0.
  • *
  • The publishedOn parameter is set.
  • *
  • The confirmedOn parameter is not set.
  • *
* * @throws KuraStoreException */ public void dropAllInFlightMessages() throws KuraStoreException; /** * Deletes the messages that satisfy any of the following conditions: * *
    *
  • The value of the droppedOn parameter is set and is more than * purgeAgeSeconds in the past.
  • *
  • The value of the confirmedOn parameter is set and is more * than * purgeAgeSeconds in the past.
  • *
  • The value of the QoS parameter is 0 and * publishedOn is set and is more than purgeAgeSeconds * in the * past.
  • *
* * @param purgeAgeSeconds the purge age in seconds. * @throws KuraStoreException */ public void deleteStaleMessages(int purgeAgeSeconds) throws KuraStoreException; /** * Closes the message store, releasing any runtime resources allocated for it. */ public void close(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/MessageStoreProvider.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.message.store.provider; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.connection.listener.ConnectionListener; import org.osgi.annotation.versioning.ProviderType; /** * Represents a service that allows to create {@link MessageStore} instances. * * @since 2.5 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface MessageStoreProvider { /** * Opens or creates a {@link MessageStore} instance with the given name. Invoking * this method could allocate the resources required to support the returned {@link MessageStore} instance (for * example tables in a RDBMS).* * * @param name * the store name. * @return the opened {@link MessageStore} * @throws KuraStoreException */ public MessageStore openMessageStore(String name) throws KuraStoreException; /** * Adds a {@link ConnectionListener}. A typical behavior of a client of this listener is to close the currently open * {@link MessageStore} instances when a {@link ConnectionListener#disconnected()} event is received. * * @param listener * to add * * @since 2.5.0 */ public void addListener(ConnectionListener listener); /** * Removes a {@link ConnectionListener} * * @param listener * to remove * * @since 2.5.0 */ public void removeListener(ConnectionListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/message/store/provider/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs for creating message stores suitable to support the default * Kura {@link org.eclipse.kura.data.DataService} implementation. * * @since 2.5 */ package org.eclipse.kura.message.store.provider; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/ConnectionInfo.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * Interface for network interface 'connection info'. At runtime an interface * may be associated with gateways or DNS but the interface itself may not be * active. If this is the case the ConnectionInfo class is used to keep all * relevant information in the event that this interface should become the * active one. This is necessary because many operating systems to not persist * this information. * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface ConnectionInfo { /** * Gets the gateway address associated with this interface * * @return A IP4Address representing the gateway if it is not null */ public IP4Address getGateway(); /** * Gets the DNS addresses associated with this interface * * @return A List of IP4Address objects representing the DNS of this interface. * If there are none it returns an * empty list. */ public List getDnsServers(); /** * Gets the interface name associated with this connection information * * @return The interface name associated with this connection information */ public String getIfaceName(); /** * Reports IP address * * @return IP address as {@link IP4Address} */ public IP4Address getIpAddress(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/EthernetInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Network interface for Ethernet cards. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface EthernetInterface extends NetInterface { /** * Indicates whether the physical carrier is found (e.g. whether a cable is plugged in or not). * * @return */ public boolean isLinkUp(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/EthernetMonitorService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Placeholder for the EthernetLinkStateMonitorService * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface EthernetMonitorService { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IP4Address.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.net.UnknownHostException; import org.osgi.annotation.versioning.ProviderType; /** * This class represents an Internet Protocol version 4 (IPv4) address. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class IP4Address extends IPAddress { IP4Address(byte[] addr, java.net.InetAddress jnAddress) { super(addr, jnAddress); } /** * Returns the default IPv4 address (0.0.0.0/0). * * @return the 0.0.0.0/0 IPv4 address * @throws UnknownHostException * @since 2.6 */ public static IP4Address getDefaultAddress() throws UnknownHostException { return (IP4Address) IPAddress.parseHostAddress("0.0.0.0"); } @Override public String toString() { return getHostAddress(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IP6Address.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.net.UnknownHostException; import org.osgi.annotation.versioning.ProviderType; /** * This class represents an Internet Protocol version 6 (IPv6) address. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class IP6Address extends IPAddress { IP6Address(byte[] addr, java.net.InetAddress jnAddress) { super(addr, jnAddress); } /** * Returns the default IPv6 address (::/0). * * @return the ::/0 IPv6 address * @throws UnknownHostException * @since 2.6 */ public static IP6Address getDefaultAddress() throws UnknownHostException { return (IP6Address) IPAddress.parseHostAddress("::"); } /** * Utility routine to check if the InetAddress is an IPv4 compatible IPv6 * address. * * @return a boolean indicating if the InetAddress is an IPv4 compatible IPv6 * address; or false if address is IPv4 * address. */ public boolean isIPv4CompatibleAddress() { return ((java.net.Inet6Address) this.javaNetAddress).isIPv4CompatibleAddress(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/IPAddress.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; import org.osgi.annotation.versioning.ProviderType; import com.google.common.net.InetAddresses; /** * This class represents an Internet Protocol (IP) address. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class IPAddress { private final byte[] address; protected java.net.InetAddress javaNetAddress; IPAddress(byte[] address, java.net.InetAddress jnAddress) { this.address = address; this.javaNetAddress = jnAddress; } /** * Returns an InetAddress object given the raw IP address. * The argument is in network byte order: the highest order byte of the address * is in getAddress()[0]. * This method doesn't block, i.e. no reverse name service lookup is performed. *
* IPv4 address byte array must be 4 bytes long and IPv6 byte array must be 16 * bytes long * * @param addr * - the raw IP address in network byte order * @return an InetAddress object created from the raw IP address. */ public static IPAddress getByAddress(byte[] addr) throws UnknownHostException { IPAddress result = null; java.net.InetAddress jnetAddr = java.net.InetAddress.getByAddress(addr); if (jnetAddr instanceof java.net.Inet4Address) { result = new IP4Address(addr, jnetAddr); } else if (jnetAddr instanceof java.net.Inet6Address) { result = new IP6Address(addr, jnetAddr); } return result; } // TODO - only works on IPv4 now public static IPAddress getByAddress(int addr) throws UnknownHostException { StringBuffer sb = new StringBuffer(); for (int shift = 24; shift > 0; shift -= 8) { // process 3 bytes, from high order byte down sb.append(Integer.toString(addr >>> shift & 0xff)); sb.append('.'); } sb.append(Integer.toString(addr & 0xff)); InetAddress jnetAddr = InetAddress.getByName(sb.toString()); return getByAddress(jnetAddr.getAddress()); } /** * Parse a literal representation of an IP address and returns the * corresponding IPAddress class. * * @param hostAddress * @return */ public static IPAddress parseHostAddress(String hostAddress) throws UnknownHostException { if (hostAddress != null && !hostAddress.isEmpty() && !InetAddresses.isInetAddress(hostAddress)) { throw new UnknownHostException("Invalid IP address: " + hostAddress); } InetAddress jnetAddr = InetAddress.getByName(hostAddress); return getByAddress(jnetAddr.getAddress()); } /** * Returns the raw IP address of this InetAddress object. * The result is in network byte order: the highest order byte of the address is * in getAddress()[0]. * * @return the raw IP address of this object. */ public byte[] getAddress() { return this.address; } /** * Returns the IP address string in textual presentation. * * @return the raw IP address in a string format. */ public String getHostAddress() { return this.javaNetAddress.getHostAddress(); } /** * Utility routine to check if the InetAddress in a wildcard address. * * @return a boolean indicating if the Inetaddress is a wildcard address. */ public boolean isAnyLocalAddress() { return this.javaNetAddress.isAnyLocalAddress(); } /** * Utility routine to check if the InetAddress is an link local address. * * @return a boolean indicating if the InetAddress is a link local address; or * false if address is not a link local * unicast address. */ public boolean isLinkLocalAddress() { return this.javaNetAddress.isLinkLocalAddress(); } /** * Utility routine to check if the InetAddress is a loopback address. * * @return a boolean indicating if the InetAddress is a loopback address; or * false otherwise. */ public boolean isLoopbackAddress() { return this.javaNetAddress.isLoopbackAddress(); } /** * Utility routine to check if the multicast address has global scope. * * @return a boolean indicating if the address has is a multicast address of * global scope, false if it is not of * global scope or it is not a multicast address */ public boolean isMCGlobal() { return this.javaNetAddress.isMCGlobal(); } /** * Utility routine to check if the multicast address has link scope. * * @return a boolean indicating if the address has is a multicast address of * link-local scope, false if it is not of * link-local scope or it is not a multicast address */ public boolean isMCLinkLocal() { return this.javaNetAddress.isMCLinkLocal(); } /** * Utility routine to check if the multicast address has node scope. * * @return a boolean indicating if the address has is a multicast address of * node-local scope, false if it is not of * node-local scope or it is not a multicast address */ public boolean isMCNodeLocal() { return this.javaNetAddress.isMCNodeLocal(); } /** * Utility routine to check if the multicast address has organization scope. * * @return a boolean indicating if the address has is a multicast address of * organization-local scope, false if it * is not of organization-local scope or it is not a multicast address */ public boolean isMCOrgLocal() { return this.javaNetAddress.isMCOrgLocal(); } /** * Utility routine to check if the multicast address has site scope. * * @return a boolean indicating if the address has is a multicast address of * site-local scope, false if it is not of * site-local scope or it is not a multicast address */ public boolean isMCSiteLocal() { return this.javaNetAddress.isMCSiteLocal(); } /** * Utility routine to check if the InetAddress is an IP multicast address. * * @return */ public boolean isMulticastAddress() { return this.javaNetAddress.isMulticastAddress(); } /** * Utility routine to check if the InetAddress is a site local address.} * * @return a boolean indicating if the InetAddress is a site local address; or * false if address is not a site local * unicast address. */ public boolean isSiteLocalAddress() { return this.javaNetAddress.isSiteLocalAddress(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(this.address); result = prime * result + (this.javaNetAddress == null ? 0 : this.javaNetAddress.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } IPAddress other = (IPAddress) obj; if (!Arrays.equals(this.address, other.address)) { return false; } if (this.javaNetAddress == null) { if (other.javaNetAddress != null) { return false; } } else if (!this.javaNetAddress.equals(other.javaNetAddress)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/LoopbackInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Placeholder for a LoopbackInterface * * @param * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface LoopbackInterface extends NetInterface { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for all network configuration classes * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetConfig { /** * Checks whether or not this configuration is valid. * * @return true if the configuration is valid, otherwise false */ public boolean isValid(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv4-based configurations of network interfaces * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetConfig4 extends NetConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv6-based configurations of network interfaces * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetConfig6 extends NetConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Base class for configuration of network interfaces. * The two subclasses NetConfigIP4 and NetConfigIP6 represent * configurations of IPv4 and IPv6 addresses respectively. * * @param * IPv4 or IPv6 address * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class NetConfigIP implements NetConfig { private NetInterfaceStatus status; private boolean autoConnect; private boolean dhcp; private T address; private short networkPrefixLength; private T subnetMask; private T gateway; private List dnsServers; private List domains; private Map properties; NetConfigIP(NetInterfaceStatus status, boolean autoConnect) { this.status = status; this.autoConnect = autoConnect; this.dhcp = false; this.address = null; this.networkPrefixLength = -1; this.subnetMask = null; this.gateway = null; this.dnsServers = new ArrayList<>(); this.domains = new ArrayList<>(); this.properties = new HashMap<>(); } NetConfigIP(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) { this.status = status; this.autoConnect = autoConnect; this.dhcp = dhcp; this.address = null; this.networkPrefixLength = -1; this.subnetMask = null; this.gateway = null; this.dnsServers = new ArrayList<>(); this.domains = new ArrayList<>(); this.properties = new HashMap<>(); } NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, short networkPrefixLength, T gateway) throws KuraException { this.status = status; this.autoConnect = autoConnect; this.dhcp = false; this.address = address; this.networkPrefixLength = networkPrefixLength; this.subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength); this.gateway = gateway; this.dnsServers = new ArrayList<>(); this.domains = new ArrayList<>(); this.properties = new HashMap<>(); } NetConfigIP(NetInterfaceStatus status, boolean autoConnect, T address, T subnetMask, T gateway) throws KuraException { this.status = status; this.autoConnect = autoConnect; this.dhcp = false; this.address = address; this.networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress()); this.subnetMask = subnetMask; this.gateway = gateway; this.dnsServers = new ArrayList<>(); this.domains = new ArrayList<>(); this.properties = new HashMap<>(); } /** * Return the NetInterfaceStatus of this configuration * * @return */ public NetInterfaceStatus getStatus() { return this.status; } /** * Sets the NetInterfaceStatus to be used for the network interface * * @param status */ public void setStatus(NetInterfaceStatus status) { this.status = status; } public boolean isAutoConnect() { return this.autoConnect; } public void setAutoConnect(boolean autoConnect) { this.autoConnect = autoConnect; } public boolean isDhcp() { return this.dhcp; } /** * Sets whether of not this configuration should be a dhcp client. If dhcp * is set to true it overrides and static configuration that is present in * the configuration. * * @param dhcp * whether or not dhcp client mode should be used */ public void setDhcp(boolean dhcp) { this.dhcp = dhcp; } /** * Returns the address that should be statically assigned to the interface. * The returned address is IP4Address or IP6Address depending on * the NetConfigIP instance used. This is only used if dhcp is set to false. * * @return the static address for the interface */ public T getAddress() { return this.address; } /** * Sets the static address to be assigned to the interface. * The address should IP4Address or IP6Address depending on * the NetConfigIP instance used. This is only used if dhcp is set to false. * * @param address * - address to be statically assigned to the interface */ public void setAddress(T address) { this.address = address; } /** * Return the prefix to be used for the network interface * * @return */ public short getNetworkPrefixLength() { return this.networkPrefixLength; } /** * Sets the prefix length to be used for the network interface * * @param networkPrefixLength * @throws KuraException */ public void setNetworkPrefixLength(short networkPrefixLength) throws KuraException { this.networkPrefixLength = networkPrefixLength; this.subnetMask = calculateNetmaskFromNetworkPrefix(networkPrefixLength); } /** * Return the prefix to be used for the network interface * * @return */ public T getSubnetMask() { return this.subnetMask; } /** * Sets the subnet mask to be used for the network interface * * @param subnetMask * @throws KuraException */ public void setSubnetMask(T subnetMask) throws KuraException { this.networkPrefixLength = calculateNetworkPrefixFromNetmask(subnetMask.getHostAddress()); this.subnetMask = subnetMask; } /** * Returns the address of the gateway to be used for the interface * * @return */ public T getGateway() { return this.gateway; } /** * Sets the gateway to be used for the interface * * @param gateway */ public void setGateway(T gateway) { this.gateway = gateway; } /** * Returns the list of Name Servers to be associated to the interface. * The returned addresses are IP4Address or IP6Address depending on * the NetConfigIP instance used. This is only used if dhcp is set to false. * * @return list of address for the DNS Servers */ public List getDnsServers() { if (this.dnsServers != null) { return Collections.unmodifiableList(this.dnsServers); } else { return null; } } /** * Sets the list of Name Servers to be associated to the interface. * The addresses are IP4Address or IP6Address depending on * the NetConfigIP instance used. This is only used if dhcp is set to false. */ public void setDnsServers(List dnsServers) { this.dnsServers = dnsServers; } /** * Returns the list of DNS domains to be associated to the interface. * This is only used if dhcp is set to false. * * @return - list of DNS domains */ public List getDomains() { if (this.domains != null) { return Collections.unmodifiableList(this.domains); } else { return null; } } /** * Sets the list of DNS domains to be associated to the interface. * This is only used if dhcp is set to false. * * @param domains */ public void setDomains(List domains) { this.domains = domains; } public Map getProperties() { if (this.properties != null) { return Collections.unmodifiableMap(this.properties); } else { return null; } } public void setProperties(Map properties) { this.properties = properties; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.address == null ? 0 : this.address.hashCode()); result = prime * result + (this.autoConnect ? 1231 : 1237); result = prime * result + (this.dhcp ? 1231 : 1237); result = prime * result + (this.dnsServers == null ? 0 : this.dnsServers.hashCode()); result = prime * result + (this.domains == null ? 0 : this.domains.hashCode()); result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode()); result = prime * result + this.networkPrefixLength; result = prime * result + (this.properties == null ? 0 : this.properties.hashCode()); result = prime * result + (this.status == null ? 0 : this.status.hashCode()); result = prime * result + (this.subnetMask == null ? 0 : this.subnetMask.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } @SuppressWarnings("rawtypes") NetConfigIP other = (NetConfigIP) obj; if (this.address == null) { if (other.address != null) { return false; } } else if (!this.address.equals(other.address)) { return false; } if (this.autoConnect != other.autoConnect) { return false; } if (this.dhcp != other.dhcp) { return false; } if (this.dnsServers == null) { if (other.dnsServers != null) { return false; } } else if (!this.dnsServers.equals(other.dnsServers)) { return false; } if (this.domains == null) { if (other.domains != null) { return false; } } else if (!this.domains.equals(other.domains)) { return false; } if (this.gateway == null) { if (other.gateway != null) { return false; } } else if (!this.gateway.equals(other.gateway)) { return false; } if (this.networkPrefixLength != other.networkPrefixLength) { return false; } if (this.properties == null) { if (other.properties != null) { return false; } } else if (!this.properties.equals(other.properties)) { return false; } if (this.status != other.status) { return false; } if (this.subnetMask == null) { if (other.subnetMask != null) { return false; } } else if (!this.subnetMask.equals(other.subnetMask)) { return false; } return true; } @Override public boolean isValid() { // FIXME if (this.dhcp) { return true; } else { try { this.address.getHostAddress(); } catch (Exception e) { return false; } for (IPAddress dns : this.dnsServers) { try { dns.getHostAddress(); } catch (Exception e) { return false; } } // if we got here... return true; } } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("NetConfigIP [status="); builder.append(this.status); builder.append(", autoConnect="); builder.append(this.autoConnect); builder.append(", dhcp="); builder.append(this.dhcp); builder.append(", address="); builder.append(this.address); builder.append(", networkPrefixLength="); builder.append(this.networkPrefixLength); builder.append(", subnetMask="); builder.append(this.subnetMask); builder.append(", gateway="); builder.append(this.gateway); builder.append(", dnsServers="); builder.append(this.dnsServers); builder.append(", domains="); builder.append(this.domains); builder.append(", properties="); builder.append(this.properties); builder.append("]"); return builder.toString(); } // TODO - only works on IPv4 now private short calculateNetworkPrefixFromNetmask(String netmask) throws KuraException { if (netmask == null) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "netmask is null"); } int netmaskValue = 0; StringTokenizer st = new StringTokenizer(netmask, "."); for (int i = 24; i >= 0; i -= 8) { netmaskValue = netmaskValue | Integer.parseInt(st.nextToken()) << i; } boolean hitZero = false; int displayMask = 1 << 31; int count = 0; for (int c = 1; c <= 32; c++) { if ((netmaskValue & displayMask) == 0) { hitZero = true; } else { if (hitZero) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "received invalid mask: " + netmask); } count++; } netmaskValue <<= 1; } return (short) count; } // TODO - only works on IPv4 now private T calculateNetmaskFromNetworkPrefix(int networkPrefixLength) throws KuraException { if (networkPrefixLength < 0) { return null; } int mask = ~((1 << 32 - networkPrefixLength) - 1); StringBuilder sb = new StringBuilder(15); for (int shift = 24; shift > 0; shift -= 8) { // process 3 bytes, from high order byte down. sb.append(Integer.toString(mask >>> shift & 0xff)); sb.append('.'); } sb.append(Integer.toString(mask & 0xff)); try { @SuppressWarnings("unchecked") T netmask = (T) IPAddress.parseHostAddress(sb.toString()); return netmask; } catch (UnknownHostException e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Configuration for a network interface based on IPv4 addresses. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class NetConfigIP4 extends NetConfigIP implements NetConfig4 { private List winsServers; public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect) { super(status, autoConnect); this.winsServers = new ArrayList<>(); } public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) { super(status, autoConnect, dhcp); this.winsServers = new ArrayList<>(); } public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, IP4Address address, short networkPrefixLength, IP4Address gateway) throws KuraException { super(status, autoConnect, address, networkPrefixLength, gateway); this.winsServers = new ArrayList<>(); } public NetConfigIP4(NetInterfaceStatus status, boolean autoConnect, IP4Address address, IP4Address subnetMask, IP4Address gateway) throws KuraException { super(status, autoConnect, address, subnetMask, gateway); this.winsServers = new ArrayList<>(); } /** * Returns the list of Windows Servers to be associated with the interface * * @return */ public List getWinsServers() { if (this.winsServers != null) { return Collections.unmodifiableList(this.winsServers); } else { return null; } } /** * Sets the list of Windows Servers to be associated with the interface * * @param winsServers */ public void setWinsServers(List winsServers) { this.winsServers = winsServers; } @Override public boolean isValid() { return super.isValid(); } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("NetConfigIP4 [winsServers="); builder.append(this.winsServers); builder.append(", super.toString()="); builder.append(super.toString()); builder.append("]"); return builder.toString(); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (this.winsServers == null ? 0 : this.winsServers.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } NetConfigIP4 other = (NetConfigIP4) obj; if (this.winsServers == null) { if (other.winsServers != null) { return false; } } else if (!this.winsServers.equals(other.winsServers)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Configuration for a network interface based on IPv6 addresses. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class NetConfigIP6 extends NetConfigIP implements NetConfig6 { /** * Empty Constructor */ public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect) { super(status, autoConnect); } /** * Constructor for a DHCP Client Configuration for a * network interface based on IPv6 addresses. * * @param dhcp * whether or not DHCP client mode should be used */ public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, boolean dhcp) { super(status, autoConnect, dhcp); } /** * Constructor for a Static Configuration for a * network interface based on IPv6 addresses. * * @param address * - address to be assigned to the interface * @param networkPrefixLength * - network prefix length to be assigned to the interface * @param gateway * - default gateway to be assigned to the interface * @throws KuraException */ public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, IP6Address address, short networkPrefixLength, IP6Address gateway) throws KuraException { super(status, autoConnect, address, networkPrefixLength, gateway); } /** * Constructor for a Static Configuration for a * network interface based on IPv6 addresses. * * @param address * - address to be assigned to the interface * @param subnetMask * - subnet mask to be assigned to the interface * @param gateway * - default gateway to be assigned to the interface * @throws KuraException */ public NetConfigIP6(NetInterfaceStatus status, boolean autoConnect, IP6Address address, IP6Address subnetMask, IP6Address gateway) throws KuraException { super(status, autoConnect, address, subnetMask, gateway); } @Override public boolean isValid() { return super.isValid(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import org.eclipse.kura.usb.UsbDevice; import org.osgi.annotation.versioning.ProviderType; /** * NetworkInterface represent a network interface of the system. * Its APIs are purposefully modeled after the java.net.NetworkInterface. * Compared to the standard Java API, this class provides additional information * such as the NetworkInterfaceType, whether the interface is provided to the system * through a USB Adapter, and additional low-level characteristics of the interface. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetInterface { /** * Returns the name of this NetworkInterface. * * @return interface name */ public String getName(); /** * Returns the type of this NetworkInterface. * * @return interface type */ public NetInterfaceType getType(); /** * The driver handling the device. * * @return */ public String getDriver(); /** * The version of the driver handling the device. * * @return */ public String getDriverVersion(); /** * The firmware version for the device. * * @return */ public String getFirmwareVersion(); /** * The current state of the device. * * @return */ public NetInterfaceState getState(); /** * Returns the hardware address (usually MAC) of the interface if it has one. * * @return a byte array containing the address or null if the address doesn't exist */ public byte[] getHardwareAddress(); /** * Returns a List of all InterfaceAddresses of this network interface. * * @return a List object with all or a subset of the InterfaceAddresss of this network interface */ public List getNetInterfaceAddresses(); /** * Returns whether a network interface is a loopback interface. * * @return true if the interface is a loopback interface. */ public boolean isLoopback(); /** * Returns whether a network interface is a point to point interface. * A typical point to point interface would be a PPP connection through a modem. * * @return true if the interface is a point to point interface. */ public boolean isPointToPoint(); /** * Returns whether this interface is a virtual interface (also called subinterface). * Virtual interfaces are, on some systems, interfaces created as a child of a physical * interface and given different settings (like address or MTU). * Usually the name of the interface will the name of the parent followed by a colon (:) * and a number identifying the child since there can be several virtual interfaces * attached to a single physical interface. * * @return true if this interface is a virtual interface. */ public boolean isVirtual(); /** * Returns whether a network interface supports multicasting or not. * * @return true if the interface supports Multicasting. */ public boolean supportsMulticast(); /** * Returns whether a network interface is up and running. * * @return true if the interface is up and running. */ public boolean isUp(); /** * Returns whether a network interface will auto connect. * * @return true if the interface will auto connect. */ public boolean isAutoConnect(); /** * Returns the Maximum Transmission Unit (MTU) of this interface * - Design speed of the device, in megabits/second (Mb/s). * * @return the value of the MTU for that interface. */ public int getMTU(); // // Kura Extensions // /** * Returns the UsbDevice which provided this NetworkInterface to the system if any. * * @return the UsbDevice providing this NetworkInterface to the system * or null if this NetworkInterface is not provided by a USB device */ public UsbDevice getUsbDevice(); /* * public String getScope(); * * public String getBroadcast(); * * public String getMask(); * * public boolean isBroadcast(); * * public boolean isRunning(); * * public boolean isMulticast(); * * public boolean isAllmulti(); * * public boolean isPromisc(); * * public long getRxPackets(); * * public long getRxErrors(); * * public long getRxDropped(); * * public long getRxOverruns(); * * public long getRxFrame(); * * public long getTxPackets(); * * public long getTxErrors(); * * public long getTxDropped(); * * public long getTxOverruns(); * * public long getTxCarrier(); * * public long getCollisions(); * * public long getTxQueueLength(); * * public long getTxBytes(); * * public long getRxBytes(); */ } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * An event raised when a new network interface has been added to the system. * * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class NetInterfaceAddedEvent extends Event { /** Topic of the NetworkInterfaceAddedEvent */ public static final String NETWORK_EVENT_INTERFACE_ADDED_TOPIC = "org/eclipse/kura/net/NetworkEvent/interface/ADDED"; /** Name of the property to access the network interface name */ public static final String NETWORK_EVENT_INTERFACE_PROPERTY = "network.interface"; public NetInterfaceAddedEvent(Map properties) { super(NETWORK_EVENT_INTERFACE_ADDED_TOPIC, properties); } /** * Returns the name of the added interface. * * @return */ public String getInterfaceName() { return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddress.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a Network Interface address as currently running on the system * In short it's an IP address, a subnet mask and a broadcast address when the address is an IPv4 one. * An IP address and a network prefix length in the case of IPv6 address. * Both IPv4 and IPv6 addresses will have a gateway and one or more DNS addresses. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetInterfaceAddress { /** * Returns an InetAddress for this address. * * @return the address */ public IPAddress getAddress(); /** * Returns the network prefix length for this address. * This is also known as the subnet mask in the context of IPv4 addresses. * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0) or 24 (255.255.255.0). * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10) * * @return a short representing the prefix length for the subnet of that address. */ public short getNetworkPrefixLength(); /** * Returns the network mask for this address * Typical IPv4 values would be 255.0.0.0, 255.255.0.0 or 255.255.255.0. * Typical IPv6 values would be ::1/128 or fe80::203:baff:fe27:1243/10 * * @return an IPaddress representing the subnet mask of that address */ public IPAddress getNetmask(); /** * Returns the InetAddress for the gateway. * * @return the gateway address */ public IPAddress getGateway(); /** * Returns an InetAddress for the broadcast address for this InterfaceAddress. * * @return the broadcast address */ public IPAddress getBroadcast(); /** * Gets the list of DNS servers associated with this interface * * @return the list of DNS servers */ public List getDnsServers(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceAddressConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * Extends a NetInterfaceAddress which is status as currently running on the system with the * interface's configuration in the form of a List of NetConfig objects. The configuration * and the status may differ based on environmental conditions and this is why configuration * is modeled separately. For example, an interface could be configured as a DHCP client. * In this case, the configuration would not include an IP address. However, the 'status' in * the NetInterfaceAddress would because the interface does have an IP - just not one that is * configured because it is dynamically assigned by the DHCP server. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetInterfaceAddressConfig extends NetInterfaceAddress { /** * Returns a List of NetConfig Objects associated with a given NetInterfaceAddressConfig * for a given NetInterface * * @return the NetConfig Objects associated with the NetInterfaceAddressConfig */ public List getConfigs(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Marker class for NetInterfaceConfig objects. * Network interfaces implementing this maker will return addresses of type NetInterfaceAddressConfig in their * getNetInterfaceAddresses() method. * NetInterfaceAddressConfig complements NetInterfaceAddress, which provides the current addresses associated to the * interface, with the NetConfig objects. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetInterfaceConfig extends NetInterface { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceRemovedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * An event raised when a network interface has been removed from the system. * * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class NetInterfaceRemovedEvent extends Event { /** Topic of the NetworkInterfaceRemovedEvent */ public static final String NETWORK_EVENT_INTERFACE_REMOVED_TOPIC = "org/eclipse/kura/net/NetworkEvent/interface/REMOVED"; /** Name of the property to access the network interface name */ public static final String NETWORK_EVENT_INTERFACE_PROPERTY = "network.interface"; public NetInterfaceRemovedEvent(Map properties) { super(NETWORK_EVENT_INTERFACE_REMOVED_TOPIC, properties); } /** * Returns the name of the removed interface. * * @return */ public String getInterfaceName() { return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceState.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * The current state of the a NetworkInterface. */ public enum NetInterfaceState { /** The device is in an unknown state. */ UNKNOWN(0), /** The device is recognized but not managed by NetworkManager. */ UNMANAGED(10), /** The device cannot be used (carrier off, rfkill, etc). */ UNAVAILABLE(20), /** The device is not connected. */ DISCONNECTED(30), /** The device is preparing to connect. */ PREPARE(40), /** The device is being configured. */ CONFIG(50), /** The device is awaiting secrets necessary to continue connection. */ NEED_AUTH(60), /** The IP settings of the device are being requested and configured. */ IP_CONFIG(70), /** The device's IP connectivity ability is being determined. */ IP_CHECK(80), /** The device is waiting for secondary connections to be activated. */ SECONDARIES(90), /** The device is active. */ ACTIVATED(100), /** The device's network connection is being torn down. */ DEACTIVATING(110), /** The device is in a failure state following an attempt to activate it. */ FAILED(120); private int code; private NetInterfaceState(int code) { this.code = code; } public static NetInterfaceState parseCode(int code) { for (NetInterfaceState state : NetInterfaceState.values()) { if (state.code == code) { return state; } } return null; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceStateChangedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Event raised when the state of a network interface has changed. * * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class NetInterfaceStateChangedEvent extends Event { /** Topic of the NetworkStateChangedEvent */ public static final String NETWORK_EVENT_INTERFACE_STATE_CHANGED_TOPIC = "org/eclipse/kura/net/NetworkEvent/interface/STATE_CHANGED"; /** Name of the property to access the network interface name */ public static final String NETWORK_EVENT_INTERFACE_PROPERTY = "network.interface"; /** Name of the property to access the new network state */ public static final String NETWORK_EVENT_NEW_STATE_PROPERTY = "network.state.new"; /** Name of the property to access the old network state */ public static final String NETWORK_EVENT_OLD_STATE_PROPERTY = "network.state.old"; /** Name of the property to access the reason of the change */ public static final String NETWORK_EVENT_STATE_CHANGE_REASON_PROPERTY = "network.state.change.reason"; public NetInterfaceStateChangedEvent(Map properties) { super(NETWORK_EVENT_INTERFACE_STATE_CHANGED_TOPIC, properties); } /** * Returns the network interface name. * * @return */ public String getInterfaceName() { return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY); } /** * Returns the new network interface state. * * @return */ public NetInterfaceState getNewState() { return (NetInterfaceState) getProperty(NETWORK_EVENT_NEW_STATE_PROPERTY); } /** * Returns the old network interface state. * * @return */ public NetInterfaceState getOldState() { return (NetInterfaceState) getProperty(NETWORK_EVENT_OLD_STATE_PROPERTY); } /** * Returns the reason for the state transition. * * @return */ public Reason getReason() { return (Reason) getProperty(NETWORK_EVENT_STATE_CHANGE_REASON_PROPERTY); } public enum Reason { /** The reason for the device state change is unknown. */ REASON_UNKNOWN, /** The state change is normal. */ REASON_NONE, /** The device is now managed. */ REASON_NOW_MANAGED, /** The device is no longer managed. */ REASON_NOW_UNMANAGED, /** The device could not be readied for configuration. */ REASON_CONFIG_FAILED, /** * IP configuration could not be reserved (no available address, timeout, etc). */ REASON_CONFIG_UNAVAILABLE, /** The IP configuration is no longer valid. */ REASON_CONFIG_EXPIRED, /** Secrets were required, but not provided. */ REASON_NO_SECRETS, /** * The 802.1X supplicant disconnected from the access point or authentication * server. */ REASON_SUPPLICANT_DISCONNECT, /** Configuration of the 802.1X supplicant failed. */ REASON_SUPPLICANT_CONFIG_FAILED, /** The 802.1X supplicant quit or failed unexpectedly. */ REASON_SUPPLICANT_FAILED, /** The 802.1X supplicant took too long to authenticate. */ REASON_SUPPLICANT_TIMEOUT, /** The PPP service failed to start within the allowed time. */ REASON_PPP_START_FAILED, /** The PPP service disconnected unexpectedly. */ REASON_PPP_DISCONNECT, /** The PPP service quit or failed unexpectedly. */ REASON_PPP_FAILED, /** The DHCP service failed to start within the allowed time. */ REASON_DHCP_START_FAILED, /** The DHCP service reported an unexpected error. */ REASON_DHCP_ERROR, /** The DHCP service quit or failed unexpectedly. */ REASON_DHCP_FAILED, /** The shared connection service failed to start. */ REASON_SHARED_START_FAILED, /** The shared connection service quit or failed unexpectedly. */ REASON_SHARED_FAILED, /** The AutoIP service failed to start. */ REASON_AUTOIP_START_FAILED, /** The AutoIP service reported an unexpected error. */ REASON_AUTOIP_ERROR, /** The AutoIP service quit or failed unexpectedly. */ REASON_AUTOIP_FAILED, /** Dialing failed because the line was busy. */ REASON_MODEM_BUSY, /** Dialing failed because there was no dial tone. */ REASON_MODEM_NO_DIAL_TONE, /** Dialing failed because there was carrier. */ REASON_MODEM_NO_CARRIER, /** Dialing timed out. */ REASON_MODEM_DIAL_TIMEOUT, /** Dialing failed. */ REASON_MODEM_DIAL_FAILED, /** Modem initialization failed. */ REASON_MODEM_INIT_FAILED, /** Failed to select the specified GSM APN. */ REASON_GSM_APN_FAILED, /** Not searching for networks. */ REASON_GSM_REGISTRATION_NOT_SEARCHING, /** Network registration was denied.* */ REASON_GSM_REGISTRATION_DENIED, /** Network registration timed out. */ REASON_GSM_REGISTRATION_TIMEOUT, /** Failed to register with the requested GSM network. */ REASON_GSM_REGISTRATION_FAILED, /** PIN check failed. */ REASON_GSM_PIN_CHECK_FAILED, /** Necessary firmware for the device may be missing. */ REASON_FIRMWARE_MISSING, /** The device was removed. */ REASON_REMOVED, /** NetworkManager went to sleep. */ REASON_SLEEPING, /** The device's active connection was removed or disappeared. */ REASON_CONNECTION_REMOVED, /** A user or client requested the disconnection. */ REASON_USER_REQUESTED, /** The device's carrier/link changed. */ REASON_CARRIER, /** The device's existing connection was assumed. */ REASON_CONNECTION_ASSUMED, /** The 802.1x supplicant is now available. */ REASON_SUPPLICANT_AVAILABLE, /** The modem could not be found. */ REASON_MODEM_NOT_FOUND, /** The Bluetooth connection timed out or failed. */ REASON_BT_FAILED, /** GSM Modem's SIM Card not inserted. */ REASON_GSM_SIM_NOT_INSERTED, /** GSM Modem's SIM Pin required. */ REASON_GSM_SIM_PIN_REQUIRED, /** GSM Modem's SIM Puk required. */ REASON_GSM_SIM_PUK_REQUIRED, /** GSM Modem's SIM wrong */ REASON_GSM_SIM_WRONG, /** InfiniBand device does not support connected mode. */ REASON_INFINIBAND_MODE, /** A dependency of the connection failed. */ REASON_DEPENDENCY_FAILED, /** Problem with the RFC 2684 Ethernet over ADSL bridge. */ REASON_BR2684_FAILED; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * Used to track interface configuration status */ public enum NetInterfaceStatus { /** IPv4 configuration is disabled **/ netIPv4StatusDisabled, /** * IPv4 configuration is not managed by Kura * * @since 1.4 **/ netIPv4StatusUnmanaged, /** * IPv4 configuration only at Layer 2 of the OSI model * * @since 1.4 **/ netIPv4StatusL2Only, /** IPv4 configuration is enabled as a LAN interface **/ netIPv4StatusEnabledLAN, /** IPv4 configuration is enabled as a WAN interface **/ netIPv4StatusEnabledWAN, /** IPv4 configuration is unknown **/ netIPv4StatusUnknown, /** IPv6 configuration is disabled **/ netIPv6StatusDisabled, /** * IPv6 configuration is not managed by Kura * * @since 1.4 **/ netIPv6StatusUnmanaged, /** * IPv6 configuration only at Layer 2 of the OSI model * * @since 1.4 **/ netIPv6StatusL2Only, /** IPv6 configuration is enabled as a LAN interface **/ netIPv6StatusEnabledLAN, /** IPv6 configuration is enabled as a WAN interface **/ netIPv6StatusEnabledWAN, /** IPv6 configuration is unknown **/ netIPv6StatusUnknown; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetInterfaceType.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * Used to store network interface types */ public enum NetInterfaceType { /** The device type is unknown. */ UNKNOWN, /** The device is wired Ethernet device. */ ETHERNET, /** The device is an 802.11 WiFi device. */ WIFI, /** Unused */ UNUSED1, /** Unused */ UNUSED2, /** The device is Bluetooth device that provides PAN or DUN capabilities. */ BT, /** The device is an OLPC mesh networking device. */ OLPC_MESH, /** The device is an 802.16e Mobile WiMAX device. */ WIMAX, /** * The device is a modem supporting one or more of analog telephone, CDMA/EVDO, GSM/UMTS/HSPA, or LTE * standards to access a cellular or wireline data network. */ MODEM, /** The device is an IP-capable InfiniBand interface. */ INFINIBAND, /** The device is a bond master interface. */ BOND, /** The device is a VLAN interface. */ VLAN, /** The device is an ADSL device supporting PPPoE and PPPoATM protocols. */ ADSL, /** The device is a loopback device. */ LOOPBACK; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetProtocol.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * Used to distinguish network protocol types */ public enum NetProtocol { /** Transmission Control Protocol (TCP) **/ tcp, /** User Datagram Protocol (UDP) **/ udp } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetRouterMode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * Used to specify the route mode of each interface. * * @deprecated since version 3.0. */ @Deprecated public enum NetRouterMode { /** DHCP and NAT **/ netRouterDchpNat, /** DHCP only **/ netRouterDchp, /** NAT only **/ netRouterNat, /** OFF **/ netRouterOff; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkAdminService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Sterwen-Technology ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.dhcp.DhcpLease; import org.eclipse.kura.net.firewall.FirewallNatConfig; import org.eclipse.kura.net.firewall.FirewallOpenPortConfigIP; import org.eclipse.kura.net.firewall.FirewallPortForwardConfigIP; import org.eclipse.kura.net.wifi.WifiAccessPoint; import org.eclipse.kura.net.wifi.WifiChannel; import org.eclipse.kura.net.wifi.WifiConfig; import org.eclipse.kura.net.wifi.WifiHotspotInfo; import org.osgi.annotation.versioning.ProviderType; /** * Service API for getting and setting network interface configurations. * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface NetworkAdminService { /** * Returns a list of all of the configurations associated with all of the * interfaces on * the system. * * @return list of NetInterfaceConfigs on the system * @throws KuraException * * @deprecated since 2.4. Use {@link getNetworkInterfaceConfigs(boolean * recompute)} instead. */ @Deprecated public List> getNetworkInterfaceConfigs() throws KuraException; /** * Returns the configuration information for the specified NetworkInterface * name. * The returned NetConfig captured how the interface was configured; the * returned * list will have a NetConfig4 instance for IPv4 and an NetConfig6 instance for * IPv6. * This should not be confused with the currently active NetInterfaceAddress * associated * with the NetInterface. * * @param interfaceName * @return list of NetConfig for this interface. * * @deprecated since 2.4. Use {@link getNetworkInterfaceConfigs(String * interfaceName, boolean recompute)} instead. */ @Deprecated public List getNetworkInterfaceConfigs(String interfaceName) throws KuraException; /** * Updates the configuration of the specified EthernetInterface. * * @param interfaceName * - name of the Ethernet interface * @param autoConnect * - specifies the auto-connect value for the interface * @param mtu * - required MTU for the interface, -1 to keep the * automatic default * @throws KuraException * * @deprecated Since 2.4. Use the * {@link org.eclipse.kura.configuration.ConfigurationService} to * update the configuration of an Ethernet interface. */ @Deprecated public void updateEthernetInterfaceConfig(String interfaceName, boolean autoConnect, int mtu, List netConfigs) throws KuraException; /** * Updates the configuration of the specified WifiInterface. * * @param interfaceName * - name of the wifi interface * @param autoConnect * - specifies the auto-connect value for the interface * @throws KuraException * * @deprecated Since 2.4. Use the * {@link org.eclipse.kura.configuration.ConfigurationService} to * update the configuration of a Wifi interface. */ @Deprecated public void updateWifiInterfaceConfig(String interfaceName, boolean autoConnect, WifiAccessPoint accessPoint, List netConfigs) throws KuraException; /** * Updates the configuration of the specified ModemInterface. * * @param interfaceName * - name of the Modem interface * @param serialNum * - the modem's serial number * @param modemId * - user string to identify the modem * @param pppNumber * - ppp number to use for this interface * @param autoConnect * - specifies the auto-connect value for the interface * @param mtu * - required MTU for the interface, -1 to keep the * automatic default * @param netConfigs * - list of NetConfigs for this interface * @throws KuraException * * @deprecated Since 2.4. Use the * {@link org.eclipse.kura.configuration.ConfigurationService} to * update the configuration of a Modem interface. */ @Deprecated public void updateModemInterfaceConfig(String interfaceName, String serialNum, String modemId, int pppNumber, boolean autoConnect, int mtu, List netConfigs) throws KuraException; /** * Enables the specified interface. * * @param interfaceName * - name of the interface to be enabled. */ public void enableInterface(String interfaceName, boolean dhcp) throws KuraException; /** * Disables the specified interface. * * @param interfaceName * - name of the interface to be disabled. */ public void disableInterface(String interfaceName) throws KuraException; /** * Used to control DHCP clients on specified interfaces. * * @param interfaceName * The interface of the DHCP server to modify the state * @param enable * Whether to enable or disable the DHCP client * @throws KuraException */ public void manageDhcpClient(String interfaceName, boolean enable) throws KuraException; /** * Used to control DHCP servers on specified interfaces. * * @param interfaceName * The interface of the DHCP server to modify the state * @param enable * Whether to enable or disable the DHCP server * @throws KuraException */ public void manageDhcpServer(String interfaceName, boolean enable) throws KuraException; /** * Releases current IP address and acquires a new lease for the provided * interface. * * @param interfaceName * The interface on which to renew the lease * @throws KuraException */ public void renewDhcpLease(String interfaceName) throws KuraException; /** * Gets the firewall configuration of the system as currently specified * * @return A list of NetConfigs representing the firewall configuration * @throws KuraException */ public List getFirewallConfiguration() throws KuraException; /** * Sets the 'open port' portion of the firewall configuration * * @param firewallConfiguration * A list of FirewallOpenPortConfigIP Objects * representing the configuration to set * @throws KuraException * * @deprecated Since 2.4 */ @Deprecated public void setFirewallOpenPortConfiguration( List> firewallConfiguration) throws KuraException; /** * Sets the 'port forwarding' portion of the firewall configuration * * @param firewallConfiguration * A list of FirewallPortForwardConfigIP Objects * representing the configuration to set * @throws KuraException * * @deprecated Since 2.4 */ @Deprecated public void setFirewallPortForwardingConfiguration( List> firewallConfiguration) throws KuraException; /** * Sets the 'ip forwarding' portion of the firewall configuration * * @param natConfigs * A list of FirewallNatConfig Objects representing the * configuration to set * @throws KuraException * * @deprecated Since 2.4 */ @Deprecated public void setFirewallNatConfiguration(List natConfigs) throws KuraException; /** * Updates the Firewall configuration based on current environmental conditions. * This is * used to update the firewall in events where NAT rules need to change based on * a new WAN * interface coming up or going down. This ensures all downstream clients * utilizing NAT * on the gateway can and will maintain active Internet connections through the * gateway. * * @param gatewayIface * The new gateway interface that is now active as the WAN * interface * @throws KuraException */ public void manageFirewall(String gatewayIface) throws KuraException; /** * Obtains information for WiFi hotspots in range. * * @param ifaceName * - name of WiFi interface * @return list of hotspot information. * @throws KuraException * @since 1.2 */ public List getWifiHotspotList(String ifaceName) throws KuraException; /** * Verifies WiFi credentials by trying to establish connection with access * point. * * @param ifaceName * - name of WiFi interface * @param wifiConfig * WiFi configuration * @param tout * - timeout (in seconds) * @return status - true if credentials are correct, false * otherwise */ public boolean verifyWifiCredentials(String ifaceName, WifiConfig wifiConfig, int tout); /** * Obtains information for WiFi Frequencies. * * @param ifaceName * - name of WiFi interface * @return list of channels and frequencies. * @throws KuraException * @since 2.2 */ public List getWifiFrequencies(String ifaceName) throws KuraException; /** * Obtains information for WiFi Country code. * * @return Name of the Country Code or 00 if unknown. * @throws KuraException * @since 2.2 */ public String getWifiCountryCode() throws KuraException; /** * Information on Dynamic Frequencies Selection * * @param ifaceName * - name of WiFi interface * @return True if Dynamic Frequencies Selection is supported, false otherwise * @since 2.3 */ public boolean isWifiDFS(String ifaceName) throws KuraException; /** * Information on WiFi 802.11ac * * @param ifaceName * - name of WiFi interface * @return True if WiFi 802.11ac is supported, false otherwise. * @since 2.3 */ public boolean isWifiIEEE80211AC(String ifaceName) throws KuraException; /** * Obtains the DHCP Lease values * * @return list of ipAddresses, macAddresses, hostnames; * @throws KuraException * @since 2.3 * @deprecated since 2.6. Use {@link getDhcpLeases(String ifaceName)} instead. */ @Deprecated public List getDhcpLeases() throws KuraException; /** * Obtains the DHCP Lease values assigned by a DHCP server running on a given * network interface * * @param ifaceName the name of the network interface * @return list of ipAddresses, macAddresses, hostnames; * @throws KuraException * @since 2.6 */ public List getDhcpLeases(String ifaceName) throws KuraException; /** * Returns a list of all of the configurations associated with all of the * interfaces on * the system and their current values. * * @param recompute: * if true the configuration and current values are * recomputed. Otherwise, a cached value is returned * @return list of NetInterfaceConfigs on the system * @throws KuraException * * @since 2.4 */ public List> getNetworkInterfaceConfigs( boolean recompute) throws KuraException; /** * Returns the configuration information for the specified NetworkInterface * name. * The returned NetConfig captured how the interface was configured; the * returned * list will have a NetConfig4 instance for IPv4 and an NetConfig6 instance for * IPv6. * This should not be confused with the currently active NetInterfaceAddress * associated * with the NetInterface. * * @param interfaceName: * the name of the network interface * @param recompute: * if true the configuration are recomputed. Otherwise, a * cached value is returned * @return list of NetConfig for this interface. * * @since 2.4 */ public List getNetworkInterfaceConfigs(String interfaceName, boolean recompute) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkPair.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import org.osgi.annotation.versioning.ProviderType; /** * Model class for a 'network' that is specified by an IP and a mask. For example in the network * represented by 192.168.1.0/24 the IpAddress would be 192.168.1.0 and the mask is 24 bits or * 255.255.255.0. NetworkPairs are used in various components such as DHCP server configurations * where a network must be specified to provide addresses on. * * @param * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class NetworkPair { /** The IP Address portion of the NetworkPair **/ @SuppressWarnings({ "checkstyle:memberName", "checkstyle:visibilityModifier" }) public T m_ipAddress; /** The prefix portion of the NetworkPair **/ @SuppressWarnings({ "checkstyle:memberName", "checkstyle:visibilityModifier" }) public short m_prefix; public NetworkPair(T ipAddress, short prefix) { this.m_ipAddress = ipAddress; this.m_prefix = prefix; } public T getIpAddress() { return this.m_ipAddress; } public void setIpAddress(T ipAddress) { this.m_ipAddress = ipAddress; } public short getPrefix() { return this.m_prefix; } public void setPrefix(short prefix) { this.m_prefix = prefix; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(this.m_ipAddress.getHostAddress()).append("/").append(this.m_prefix); return sb.toString(); } @Override public boolean equals(Object o) { if (!(o instanceof NetworkPair)) { return false; } NetworkPair other = (NetworkPair) o; return (this.m_ipAddress.equals(other.m_ipAddress) && this.m_prefix == other.m_prefix); } @Override public int hashCode() { final int prime = 67; int result = 1; result = prime * result + this.m_prefix; result = prime * result + (this.m_ipAddress == null ? 0 : this.m_ipAddress.hashCode()); return result; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.modem.ModemDevice; import org.eclipse.kura.net.wifi.WifiAccessPoint; import org.eclipse.kura.usb.UsbNetDevice; import org.osgi.annotation.versioning.ProviderType; /** * The NetworkService allows to browse and configure the network interfaces of * the system. *
* NetworkService extends what is offered by the standard Java APIs by offering * information * like the NetworkInterface type - e.g. wired vs wireless vs modem - and * additional information * regarding the address of a NetworkInterface - e.g. its getway address, DNS, * and so on. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetworkService { /** * Returns the overall state of the networking subsystem * * @deprecated since 2.3 */ @Deprecated public NetworkState getState() throws KuraException; /** * Returns the state of a specific network interface * * @deprecated since 2.3 */ @Deprecated public NetInterfaceState getState(String interfaceName) throws KuraException; /** * Gets the names of all the network interface attached to the system. * * @return the names of all interfaces regardless of 'up' status */ public List getAllNetworkInterfaceNames() throws KuraException; /** * Gets the names of all the network interface attached to the system. * For each returned NetworkInterface, its currently active * InterfaceAddresses are returned. * * @return all NetworkInterfaces */ public List> getNetworkInterfaces() throws KuraException; /** * Returns the list of all available WifiAccessPoints as seen from the system. * * @return all access points accessible from the system. */ public List getAllWifiAccessPoints() throws KuraException; /** * Returns the list of the WifiAccessPoints visible from the specified wifi * network interface. * If this wifiInterfaceName is in Master mode it will return a List with one * WifiAccessPoint * which is itself. * * @param wifiInterfaceName * name of the interface used to scan for the available * access points * @return the list of the WifiAccessPoints visible from the specified wifi * network interface. */ public List getWifiAccessPoints(String wifiInterfaceName) throws KuraException; /** * Return the active NetworkIntefaces which have active connections for the * system. * * @return */ public List> getActiveNetworkInterfaces() throws KuraException; /** * Given an interface name (e.g. 'ppp0'), look up the associated usb port * * @param the * name of the ppp interface (i.e. ppp0) * @return a string representing the usb port of the modem (i.e. 1-2.3) */ public String getModemUsbPort(String pppInterfaceName); /** * Given a modem device, look up the associated ppp interface name * * @param modemDevice * @return the name of the ppp interface * @throws KuraException */ public String getModemPppPort(ModemDevice modemDevice) throws KuraException; /** * Given a usb path, look up the associated ppp interface name * * @param usbPath * a string representing the usb port (i.e. 1-2.3) * @return the name of the ppp interface * @throws KuraException * * @since 2.3 */ public String getModemPppInterfaceName(String usbPath); /** * Given a usb path, look up the associated modem device * * @param usbPath * a string representing the usb port (i.e. 1-2.3) * @return the {@link ModemDevice} attached to the specified usb port * @throws KuraException * * @since 2.3 */ public Optional getModemDevice(String usbPath); /** * Return the {@link UsbNetDevice} associated to the given network interface * name, if any. * * @param interfaceName the name of the network interface * @return an optional {@link UsbNetDevice} * * @since 2.4 */ public Optional getUsbNetDevice(String interfaceName); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkState.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; /** * The overall state of the networking subsystem. */ public enum NetworkState { /** Networking state is unknown. */ UNKNOWN(0), /** Networking is inactive and all devices are disabled. */ ASLEEP(10), /** There is no active network connection. */ DISCONNECTED(20), /** Network connections are being cleaned up. */ DISCONNECTING(30), /** A network device is connecting to a network and there is no other available network connection. */ CONNECTING(40), /** A network device is connected, but there is only link-local connectivity. */ CONNECTED_LOCAL(50), /** A network device is connected, but there is only site-local connectivity. */ CONNECTED_SITE(60), /** A network device is connected, with global network connectivity. */ CONNECTED_GLOBAL(70); private int code; private NetworkState(int code) { this.code = code; } public static NetworkState parseCode(int code) { for (NetworkState state : NetworkState.values()) { if (state.code == code) { return state; } } return null; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/NetworkStateChangedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Event raised when the state of the network has changed. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class NetworkStateChangedEvent extends Event { /** Topic of the NetworkStateChangedEvent */ public static final String NETWORK_EVENT_STATE_CHANGED_TOPIC = "org/eclipse/kura/net/NetworkEvent/STATE_CHANGED"; /** Name of the property to access the new network state */ public static final String NETWORK_EVENT_NEW_STATE_PROPERTY = "network.state"; public NetworkStateChangedEvent(Map properties) { super(NETWORK_EVENT_STATE_CHANGED_TOPIC, properties); } /** * Returns the new network state. * * @return */ public NetworkState getState() { return (NetworkState) getProperty(NETWORK_EVENT_NEW_STATE_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpLease.java ================================================ /******************************************************************************* * Copyright (c) 2022 Sterwen Technology and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Sterwen-Technology *******************************************************************************/ package org.eclipse.kura.net.dhcp; import org.osgi.annotation.versioning.ProviderType; /** * @since 2.3 */ @ProviderType public class DhcpLease { private String macAddress; private String ipAddress; private String hostname; public DhcpLease(String macAddress, String ipAddress, String hostname) { super(); this.macAddress = macAddress; this.ipAddress = ipAddress; this.hostname = hostname; } public String getMacAddress() { return macAddress; } public void setMacAddress(String macAddress) { this.macAddress = macAddress; } public String getIpAddress() { return ipAddress; } public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } public String getHostname() { return hostname; } public void setHostname(String hostname) { this.hostname = hostname; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); sb.append("MacAddress:").append(macAddress).append(", IpAddress:").append(ipAddress).append(", Hostname:").append(hostname); sb.append("]"); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServer.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Represents a DHCP server. * * @noimplement This interface is not intended to be implemented by clients. */ @FunctionalInterface @ProviderType public interface DhcpServer { /** * Returns whether or not the DhcpServer is actively running or not * * @return a boolean denoting whether or not the DhcpServer is running or not * @throws KuraException */ public boolean isRunning() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfg.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import org.osgi.annotation.versioning.ProviderType; /** * The configuration representing generic portion of DHCP server configuration. * * @noextend This class is not intended to be subclassed by clients. * @since 1.2 */ @ProviderType public class DhcpServerCfg { private String interfaceName; private boolean enabled; private int defaultLeaseTime; private int maximumLeaseTime; private boolean passDns; /** * The basic Constructor for a DhcpServerCfg * * @param interfaceName * the interface name associated with the DhcpServerConfig * @param enabled * the status of the DhcpServer as a boolean * @param defaultLeaseTime * the default lease time to issue to DHCP clients * @param maximumLeaseTime * the maximum lease time to issue to DHCP clients * @param passDns * whether or not to pass DNS to DHCP clients */ public DhcpServerCfg(String interfaceName, boolean enabled, int defaultLeaseTime, int maximumLeaseTime, boolean passDns) { super(); this.interfaceName = interfaceName; this.enabled = enabled; this.defaultLeaseTime = defaultLeaseTime; this.maximumLeaseTime = maximumLeaseTime; this.passDns = passDns; } public String getInterfaceName() { return this.interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } public boolean isEnabled() { return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public int getDefaultLeaseTime() { return this.defaultLeaseTime; } public void setDefaultLeaseTime(int defaultLeaseTime) { this.defaultLeaseTime = defaultLeaseTime; } public int getMaximumLeaseTime() { return this.maximumLeaseTime; } public void setMaximumLeaseTime(int maximumLeaseTime) { this.maximumLeaseTime = maximumLeaseTime; } public boolean isPassDns() { return this.passDns; } public void setPassDns(boolean passDns) { this.passDns = passDns; } @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append(": [").append("ifaceName=").append(this.interfaceName).append(", enabled?=").append(this.enabled) .append(", defaultLeaseTime=").append(this.defaultLeaseTime).append(", maximumLeaseTime=") .append(this.maximumLeaseTime).append(", passDNS?=").append(this.passDns).append(']'); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * The abstract representation of a 'networking' portion of DhcpServerConfig object. * * @param * is the an appropriate subclass of IPAddress * * @noextend This class is not intended to be subclassed by clients. * @since 1.2 */ @ProviderType public abstract class DhcpServerCfgIP { private T subnet; private T subnetMask; private short prefix; private T routerAddress; private T rangeStart; private T rangeEnd; private List dnsServers; /** * The basic Constructor for a DhcpServerConfigIP * * @param subnet * the subnet of the DhcpServerConfig * @param subnetMask * the subnet mask of the DhcpServerConfig * @param prefix * the network prefix associated with the DhcpServerConfig * @param routerAddress * the router IPAddress * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients if passDns is true */ public DhcpServerCfgIP(T subnet, T subnetMask, short prefix, T routerAddress, T rangeStart, T rangeEnd, List dnsServers) { super(); this.subnet = subnet; this.subnetMask = subnetMask; this.prefix = prefix; this.routerAddress = routerAddress; this.rangeStart = rangeStart; this.rangeEnd = rangeEnd; this.dnsServers = dnsServers; } public T getSubnet() { return this.subnet; } public void setSubnet(T subnet) { this.subnet = subnet; } public T getSubnetMask() { return this.subnetMask; } public void setSubnetMask(T subnetMask) { this.subnetMask = subnetMask; } public short getPrefix() { return this.prefix; } public void setPrefix(short prefix) { this.prefix = prefix; } public T getRouterAddress() { return this.routerAddress; } public void setRouterAddress(T routerAddress) { this.routerAddress = routerAddress; } public T getRangeStart() { return this.rangeStart; } public void setRangeStart(T rangeStart) { this.rangeStart = rangeStart; } public T getRangeEnd() { return this.rangeEnd; } public void setRangeEnd(T rangeEnd) { this.rangeEnd = rangeEnd; } public List getDnsServers() { return this.dnsServers; } public void setDnsServers(List dnsServers) { this.dnsServers = dnsServers; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.net.Inet4Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.List; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.IP4Address; import org.osgi.annotation.versioning.ProviderType; /** * The configuration representing a 'networking' portion of DHCP server configuration for an IPv4 network. * * @noextend This class is not intended to be subclassed by clients. * @since 1.2 */ @ProviderType public class DhcpServerCfgIP4 extends DhcpServerCfgIP { /** * The basic Constructor for a DhcpServerCfgIP4 * * @param subnet * the subnet of the DhcpServerConfig * @param subnetMask * the subnet mask of the DhcpServerConfig * @param prefix * the network prefix associated with the DhcpServerConfig * @param routerAddress * the router IPAddress * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients if passDns is true */ public DhcpServerCfgIP4(IP4Address subnet, IP4Address subnetMask, short prefix, IP4Address routerAddress, IP4Address rangeStart, IP4Address rangeEnd, List dnsServers) { super(subnet, subnetMask, prefix, routerAddress, rangeStart, rangeEnd, dnsServers); } /** * Validates DHCP pool */ public boolean isValid() throws KuraException { boolean ret = false; if (isIpAddressInSubnet(getRangeStart().getHostAddress(), getSubnet().getHostAddress(), getSubnetMask().getHostAddress()) && isIpAddressInSubnet(getRangeEnd().getHostAddress(), getSubnet().getHostAddress(), getSubnetMask().getHostAddress())) { ret = true; } return ret; } @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append(": [subnet=").append(getSubnet().getHostAddress()).append(", subnetMask=") .append(getSubnetMask().getHostAddress()).append(", prefix=").append(getPrefix()) .append(", routerAddress=").append(getRouterAddress()).append(", rangeStart=").append(getRangeStart()) .append(", rangeEnd=").append(getRangeEnd()); for (IP4Address dnsServer : getDnsServers()) { sb.append(", dnsServer=").append(dnsServer); } sb.append(']'); return sb.toString(); } private static int inet4address2int(Inet4Address inet4addr) { byte[] baInet4addr = inet4addr.getAddress(); return (baInet4addr[0] & 0xFF) << 24 | (baInet4addr[1] & 0xFF) << 16 | (baInet4addr[2] & 0xFF) << 8 | baInet4addr[3] & 0xFF; } private boolean isIpAddressInSubnet(String ip, String subnet, String netmask) throws KuraException { boolean retVal = false; try { int iIp = inet4address2int((Inet4Address) InetAddress.getByName(ip)); int iSubnet = inet4address2int((Inet4Address) InetAddress.getByName(subnet)); int iNetmask = inet4address2int((Inet4Address) InetAddress.getByName(netmask)); if ((iSubnet & iNetmask) == (iIp & iNetmask)) { retVal = true; } } catch (UnknownHostException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e); } return retVal; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerCfgIP6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.net.IP6Address; import org.osgi.annotation.versioning.ProviderType; /** * The configuration representing a 'networking' portion of DHCP server configuration for an IPv6 network. * * @noextend This class is not intended to be subclassed by clients. * @since 1.2 */ @ProviderType public class DhcpServerCfgIP6 extends DhcpServerCfgIP { /** * The basic Constructor for a DhcpServerCfgIP6 * * @param subnet * the subnet of the DhcpServerConfig * @param subnetMask * the subnet mask of the DhcpServerConfig * @param prefix * the network prefix associated with the DhcpServerConfig * @param routerAddress * the router IPAddress * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients if passDns is true */ public DhcpServerCfgIP6(IP6Address subnet, IP6Address subnetMask, short prefix, IP6Address routerAddress, IP6Address rangeStart, IP6Address rangeEnd, List dnsServers) { super(subnet, subnetMask, prefix, routerAddress, rangeStart, rangeEnd, dnsServers); } /** * class validator * */ public boolean isValid() { // TODO need to range implement validation return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for all DHCP server configuration classes * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DhcpServerConfig extends NetConfig { /** * Returns the interface name associated with this DhcpServerConfig * * @return a {@link String} representing the interface name */ public String getInterfaceName(); /** * Returns the {@link boolean} status associated with this DhcpServerConfig * * @return a {@link boolean} representing the status */ public boolean isEnabled(); /** * Returns the subnet associated with this DhcpServerConfig * * @return a {@link IPAddress } representing the subnet */ public IPAddress getSubnet(); /** * Returns the router IP address associated with this DhcpServerConfig * * @return a {@link IPAddress } representing the router IP address */ public IPAddress getRouterAddress(); /** * Returns the subnet mask associated with this DhcpServerConfig * * @return a {@link IPAddress } representing the subnet mask */ public IPAddress getSubnetMask(); /** * Returns the default lease time offered by the DHCP server * * @return the default lease time (in seconds) offered by the DHCP server */ public int getDefaultLeaseTime(); /** * Returns the maximum lease time offered by the DHCP server * * @return the maximum lease time (in seconds) offered by the DHCP server */ public int getMaximumLeaseTime(); /** * Returns the network prefix length for this DHCP server's address range * This is also known as the subnet mask in the context of IPv4 addresses. * Typical IPv4 values would be 8 (255.0.0.0), 16 (255.255.0.0) or 24 (255.255.255.0). * Typical IPv6 values would be 128 (::1/128) or 10 (fe80::203:baff:fe27:1243/10) * * @return a short representing the prefix length for the subnet of the DHCP server address range. */ public short getPrefix(); /** * Returns the starting DHCP server InetAddress to provide to DHCP clients. * * @return the starting address to provide to DHCP clients */ public IPAddress getRangeStart(); /** * Returns the ending DHCP server InetAddress to provide to DHCP clients. * * @return the ending address to provide to DHCP clients */ public IPAddress getRangeEnd(); /** * Returns whether or not DHCP clients should get DNS services. * * @return a boolean representing whether or not DHCP clients should receive DNS services. */ public boolean isPassDns(); /** * Returns the DNS servers associated with this DhcpServerConfig that will be passed to DHCP clients * * @return a {@link List } of IPAddresses that represent the DNS servers */ public List getDnsServers(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv4-based configurations of DHCP Servers * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DhcpServerConfig4 extends DhcpServerConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv6-based configurations of DHCP Servers * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DhcpServerConfig6 extends DhcpServerConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * The abstract representation of a DhcpServerConfig object. * * @param * is the an appropriate subclass of IPAddress * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class DhcpServerConfigIP implements DhcpServerConfig { private String interfaceName; private boolean enabled; private T subnet; private T routerAddress; private T subnetMask; private int defaultLeaseTime; private int maximumLeaseTime; private short prefix; private T rangeStart; private T rangeEnd; private boolean passDns; private List dnsServers; /** * The basic Constructor for a DhcpServerConfigIP * * @param interfaceName * the interface name associated with the * DhcpServerConfig * @param enabled * the status of the DhcpServer as a boolean * @param subnet * the subnet of the DhcpServerConfig * @param routerAddress * the router IPAddress * @param subnetMask * the subnet mask of the DhcpServerConfig * @param defaultLeaseTime * the default lease time to issue to DHCP clients * @param maximumLeaseTime * the maximum lease time to issue to DHCP clients * @param prefix * the network prefix associated with the * DhcpServerConfig * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param passDns * whether or not to pass DNS to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients * if passDns is true */ @Deprecated @SuppressWarnings("checkstyle:parameterNumber") public DhcpServerConfigIP(String interfaceName, boolean enabled, T subnet, T routerAddress, T subnetMask, int defaultLeaseTime, int maximumLeaseTime, short prefix, T rangeStart, T rangeEnd, boolean passDns, List dnsServers) { super(); this.interfaceName = interfaceName; this.enabled = enabled; this.subnet = subnet; this.routerAddress = routerAddress; this.subnetMask = subnetMask; this.defaultLeaseTime = defaultLeaseTime; this.maximumLeaseTime = maximumLeaseTime; this.prefix = prefix; this.rangeStart = rangeStart; this.rangeEnd = rangeEnd; this.passDns = passDns; this.dnsServers = dnsServers; } /** * The basic Constructor for a DhcpServerConfigIP * * @param dhcpServerCfg * DHCP server configuration * @param dhcpServerCfgIP * 'network' configuration * @since 1.2 */ public DhcpServerConfigIP(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP dhcpServerCfgIP) { this.interfaceName = dhcpServerCfg.getInterfaceName(); this.enabled = dhcpServerCfg.isEnabled(); this.subnet = dhcpServerCfgIP.getSubnet(); this.routerAddress = dhcpServerCfgIP.getRouterAddress(); this.subnetMask = dhcpServerCfgIP.getSubnetMask(); this.defaultLeaseTime = dhcpServerCfg.getDefaultLeaseTime(); this.maximumLeaseTime = dhcpServerCfg.getMaximumLeaseTime(); this.prefix = dhcpServerCfgIP.getPrefix(); this.rangeStart = dhcpServerCfgIP.getRangeStart(); this.rangeEnd = dhcpServerCfgIP.getRangeEnd(); this.passDns = dhcpServerCfg.isPassDns(); this.dnsServers = dhcpServerCfgIP.getDnsServers(); } @Override public String getInterfaceName() { return this.interfaceName; } /** * sets the interface name for the DhcpServerConfig * * @param interfaceName * the interface name in the form of a {@link String} */ public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } @Override public boolean isEnabled() { return this.enabled; } /** * sets the status for the DhcpServerConfig * * @param enabled * the Dhcp Server status in the form of a {@link boolean} */ public void setEnabledRouterMode(boolean enabled) { this.enabled = enabled; } @Override public T getSubnet() { return this.subnet; } /** * sets the subnet for the DhcpServerConfig * * @param subnet * the subnet in the form of a {@link IPAddress} */ public void setSubnet(T subnet) { this.subnet = subnet; } @Override public T getRouterAddress() { return this.routerAddress; } /** * sets the router IPAddress for the DhcpServerConfig * * @param routerAddress * the router IPAddress in the form of a {@link IPAddress} */ public void setRouterAddress(T routerAddress) { this.routerAddress = routerAddress; } @Override public T getSubnetMask() { return this.subnetMask; } /** * sets the subnet mask for the DhcpServerConfig * * @param subnetMask * the subnet mask in the form of a {@link IPAddress} */ public void setSubnetMask(T subnetMask) { this.subnetMask = subnetMask; } @Override public int getDefaultLeaseTime() { return this.defaultLeaseTime; } /** * sets the default lease time for DHCP clients * * @param defaultLeaseTime * the default lease time */ public void setDefaultLeaseTime(int defaultLeaseTime) { this.defaultLeaseTime = defaultLeaseTime; } @Override public int getMaximumLeaseTime() { return this.maximumLeaseTime; } /** * sets the maximum lease time for DHCP clients * * @param maximumLeaseTime * the maximum lease time */ public void setMaximumLeaseTime(int maximumLeaseTime) { this.maximumLeaseTime = maximumLeaseTime; } @Override public short getPrefix() { return this.prefix; } /** * sets the network prefix for the DhcpServerConfig * * @param prefix * the prefix */ public void setPrefix(short prefix) { this.prefix = prefix; } @Override public T getRangeStart() { return this.rangeStart; } /** * sets the starting IPAddress in the pool for the DHCP clients * * @param m_rangeStart * the starting IPAddress */ public void setRangeStart(T rangeStart) { this.rangeStart = rangeStart; } @Override public T getRangeEnd() { return this.rangeEnd; } /** * sets the ending IPAddress in the pool for the DHCP clients * * @param rangeEnd * the ending IPAddress */ public void setRangeEnd(T rangeEnd) { this.rangeEnd = rangeEnd; } @Override public boolean isPassDns() { return this.passDns; } /** * whether or not to pass DNS to DHCP clients * * @param passDns * true to pass, false to not */ public void setPassDns(boolean passDns) { this.passDns = passDns; } @Override public List getDnsServers() { return this.dnsServers; } /** * the DNS servers to pass to DHCP clients if passDns is set to true * * @param m_dnsServers * the DNS servers to pass */ public void setDnsServers(List dnsServers) { this.dnsServers = dnsServers; } @Override public boolean isValid() { if (this.interfaceName == null || !isValidSubnet()) { return false; } if (!isValidPoolRange() || !isValidLeaseTime() || this.prefix <= 0) { return false; } return true; } private boolean isValidSubnet() { return this.subnet != null && this.subnetMask != null ? true : false; } private boolean isValidPoolRange() { return this.rangeStart != null && this.rangeEnd != null ? true : false; } private boolean isValidLeaseTime() { return this.defaultLeaseTime > 0 && this.maximumLeaseTime > 0 ? true : false; } /** * Returns a string representation of the Dhcp Server Configuration. * DO NOT use it to write the service configuration file in the filesystem. */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("# enabled? ").append(this.enabled).append("\n"); sb.append("# prefix: ").append(this.prefix).append("\n"); sb.append("# pass DNS? ").append(this.passDns).append("\n\n"); sb.append("subnet " + this.subnet.getHostAddress() + " netmask " + this.subnetMask.getHostAddress() + " {\n"); // DNS servers if (this.passDns && this.dnsServers != null && !this.dnsServers.isEmpty()) { sb.append(" option domain-name-servers "); for (int i = 0; i < this.dnsServers.size(); i++) { if (this.dnsServers.get(i) != null) { sb.append(this.dnsServers.get(i).getHostAddress()); } if (i + 1 == this.dnsServers.size()) { sb.append(";\n\n"); } else { sb.append(","); } } } // interface if (this.interfaceName != null) { sb.append(" interface " + this.interfaceName + ";\n"); } // router address if (this.routerAddress != null) { sb.append(" option routers " + this.routerAddress.getHostAddress() + ";\n"); } // if DNS should not be forwarded, add the following lines if (!this.passDns) { sb.append(" ddns-update-style none;\n"); sb.append(" ddns-updates off;\n"); } // Lease times sb.append(" default-lease-time " + this.defaultLeaseTime + ";\n"); if (this.maximumLeaseTime > -1) { sb.append(" max-lease-time " + this.maximumLeaseTime + ";\n"); } // Add the pool and range sb.append(" pool {\n"); sb.append(" range " + this.rangeStart.getHostAddress() + " " + this.rangeEnd.getHostAddress() + ";\n"); sb.append(" }\n"); sb.append("}\n"); return sb.toString(); } @Override public int hashCode() { final int prime = 59; int result = super.hashCode(); result = prime * result + (this.enabled ? 1 : 0); result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode()); result = prime * result + (this.subnet == null ? 0 : this.subnet.hashCode()); result = prime * result + (this.subnetMask == null ? 0 : this.subnetMask.hashCode()); result = prime * result + (this.routerAddress == null ? 0 : this.routerAddress.hashCode()); result = prime * result + (this.rangeStart == null ? 0 : this.rangeStart.hashCode()); result = prime * result + (this.rangeEnd == null ? 0 : this.rangeEnd.hashCode()); result = prime * result + (this.dnsServers == null ? 0 : this.dnsServers.hashCode()); result = prime * result + this.defaultLeaseTime; result = prime * result + this.maximumLeaseTime; result = prime * result + this.prefix; result = prime * result + (this.passDns ? 1 : 0); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } @SuppressWarnings("rawtypes") DhcpServerConfigIP other = (DhcpServerConfigIP) obj; if (this.enabled != other.enabled) { return false; } if (this.interfaceName == null) { if (other.interfaceName != null) { return false; } } else if (!this.interfaceName.equals(other.interfaceName)) { return false; } if (this.subnet == null) { if (other.subnet != null) { return false; } } else if (!this.subnet.equals(other.subnet)) { return false; } if (this.routerAddress == null) { if (other.routerAddress != null) { return false; } } else if (!this.routerAddress.equals(other.routerAddress)) { return false; } if (this.subnetMask == null) { if (other.subnetMask != null) { return false; } } else if (!this.subnetMask.equals(other.subnetMask)) { return false; } if (this.defaultLeaseTime != other.defaultLeaseTime) { return false; } if (this.maximumLeaseTime != other.maximumLeaseTime) { return false; } if (this.prefix != other.prefix) { return false; } if (this.rangeStart == null) { if (other.rangeStart != null) { return false; } } else if (!this.rangeStart.equals(other.rangeStart)) { return false; } if (this.rangeEnd == null) { if (other.rangeEnd != null) { return false; } } else if (!this.rangeEnd.equals(other.rangeEnd)) { return false; } if (this.passDns != other.passDns) { return false; } if (this.dnsServers == null) { if (other.dnsServers != null) { return false; } } else if (!this.dnsServers.equals(other.dnsServers)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.IP4Address; import org.osgi.annotation.versioning.ProviderType; /** * The configuration representing a DHCP server configuration for an IPv4 network. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class DhcpServerConfigIP4 extends DhcpServerConfigIP implements DhcpServerConfig4 { /** * The basic Constructor for a DhcpServerConfigIP4 * * @param interfaceName * the interface name associated with the DhcpServerConfig * @param enabled * the status of the DhcpServer as a boolean * @param subnet * the subnet of the DhcpServerConfig * @param routerAddress * the router IPAddress * @param subnetMask * the subnet mask of the DhcpServerConfig * @param defaultLeaseTime * the default lease time to issue to DHCP clients * @param maximumLeaseTime * the maximum lease time to issue to DHCP clients * @param prefix * the network prefix associated with the DhcpServerConfig * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param passDns * whether or not to pass DNS to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients if passDns is true */ @Deprecated @SuppressWarnings("checkstyle:parameterNumber") public DhcpServerConfigIP4(String interfaceName, boolean enabled, IP4Address subnet, IP4Address routerAddress, IP4Address subnetMask, int defaultLeaseTime, int maximumLeaseTime, short prefix, IP4Address rangeStart, IP4Address rangeEnd, boolean passDns, List dnsServers) { super(interfaceName, enabled, subnet, routerAddress, subnetMask, defaultLeaseTime, maximumLeaseTime, prefix, rangeStart, rangeEnd, passDns, dnsServers); } /** * The basic Constructor for a DhcpServerConfigIP4 * * @param dhcpServerCfg * DHCP server configuration * @param dhcpServerCfgIP4 * 'network' configuration * @throws KuraException * @since 1.2 */ public DhcpServerConfigIP4(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP4 dhcpServerCfgIP4) throws KuraException { super(dhcpServerCfg, dhcpServerCfgIP4); if (!isValid() || !dhcpServerCfgIP4.isValid()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/DhcpServerConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dhcp; import java.util.List; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.IP6Address; import org.osgi.annotation.versioning.ProviderType; /** * The configuration representing a DHCP server configuration for an IPv6 network. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class DhcpServerConfigIP6 extends DhcpServerConfigIP implements DhcpServerConfig6 { /** * The basic Constructor for a DhcpServerConfigIP6 * * @param interfaceName * the interface name associated with the DhcpServerConfig * @param enabled * the status of the DhcpServer as a {@link boolean } * @param subnet * the subnet of the DhcpServerConfig * @param routerAddress * the router IPAddress * @param subnetMask * the subnet mask of the DhcpServerConfig * @param defaultLeaseTime * the default lease time to issue to DHCP clients * @param maximumLeaseTime * the maximum lease time to issue to DHCP clients * @param prefix * the network prefix associated with the DhcpServerConfig * @param rangeStart * the network starting address to issue to DHCP clients * @param rangeEnd * the network ending address to issue to DHCP clients * @param passDns * whether or not to pass DNS to DHCP clients * @param dnsServers * the DNS servers that will get passed to DHCP clients if passDns is true */ @Deprecated @SuppressWarnings("checkstyle:parameterNumber") public DhcpServerConfigIP6(String interfaceName, boolean enabled, IP6Address subnet, IP6Address routerAddress, IP6Address subnetMask, int defaultLeaseTime, int maximumLeaseTime, short prefix, IP6Address rangeStart, IP6Address rangeEnd, boolean passDns, List dnsServers) { super(interfaceName, enabled, subnet, routerAddress, subnetMask, defaultLeaseTime, maximumLeaseTime, prefix, rangeStart, rangeEnd, passDns, dnsServers); } /** * The basic Constructor for a DhcpServerConfigIP6 * * @param dhcpServerCfg * DHCP server configuration * @param dhcpServerCfgIP4 * 'network' configuration * @throws KuraException * @since 1.2 */ public DhcpServerConfigIP6(DhcpServerCfg dhcpServerCfg, DhcpServerCfgIP6 dhcpServerCfgIP6) throws KuraException { super(dhcpServerCfg, dhcpServerCfgIP6); if (!isValid() || !dhcpServerCfgIP6.isValid()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dhcp/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Interfaces for all DHCP server instances. * */ package org.eclipse.kura.net.dhcp; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsMonitorService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for dns server monitoring service * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface DnsMonitorService { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import java.util.Set; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The placeholder for all DNS proxy servers * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DnsServerConfig extends NetConfig { /** * returns the DNS forwarders associated with this DnsServerConfig * * @return a {@link java.util.List } of DNS forwarders */ public Set getForwarders(); /** * returns the allowed networks for resolving DNS queries * * @return a {@link java.util.List } of {@link NetworkPair } representing the networks that are allowed to * perform DNS queries */ public Set> getAllowedNetworks(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import org.osgi.annotation.versioning.ProviderType; /** * Placeholder for IPv4 DNS server configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DnsServerConfig4 extends DnsServerConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import org.osgi.annotation.versioning.ProviderType; /** * Placeholder for IPv6 DNS server configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface DnsServerConfig6 extends DnsServerConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import java.util.Set; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * Base class for DNS proxy configurations * * @param * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class DnsServerConfigIP implements DnsServerConfig { private Set forwarders; private Set> allowedNetworks; /** * Creates a DNS configuration with a default set of forwarders and a set of allowed networks * * @param forwarders * The recursive DNS servers to use * @param allowedNetworks * The LAN networks that are allowed to make queries */ public DnsServerConfigIP(Set forwarders, Set> allowedNetworks) { super(); this.forwarders = forwarders; this.allowedNetworks = allowedNetworks; } /** * Gets the current recursive domain name servers to use to resolve queries */ @Override public Set getForwarders() { return this.forwarders; } /** * Sets the current recursive domain name servers to use to resolve queries * * @param forwarders * The recursive DNS servers to use */ public void setForwarders(Set forwarders) { this.forwarders = forwarders; } /** * Gets a List of networks that are allowed to make DNS queries */ @Override public Set> getAllowedNetworks() { return this.allowedNetworks; } /** * Sets a List of networks that are allowed to make DNS queries * * @param allowedNetworks * The LAN networks that are allowed to make queries */ public void setAllowedNetworks(Set> allowedNetworks) { this.allowedNetworks = allowedNetworks; } @Override public String toString() { return "DnsServerConfigIP [m_forwarders=" + this.forwarders + ", m_allowedNetworks=" + this.allowedNetworks + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.allowedNetworks == null ? 0 : this.allowedNetworks.hashCode()); result = prime * result + (this.forwarders == null ? 0 : this.forwarders.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } DnsServerConfigIP other = (DnsServerConfigIP) obj; if (this.allowedNetworks == null) { if (other.allowedNetworks != null) { return false; } } else if (!this.allowedNetworks.equals(other.allowedNetworks)) { return false; } if (this.forwarders == null) { if (other.forwarders != null) { return false; } } else if (!this.forwarders.equals(other.forwarders)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import java.util.Set; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * DNS server configurations for IPv4 networks * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class DnsServerConfigIP4 extends DnsServerConfigIP implements DnsServerConfig4 { public DnsServerConfigIP4(Set forwarders, Set> allowedNetworks) { super(forwarders, allowedNetworks); } @Override public boolean isValid() { // TODO Auto-generated method stub return false; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/DnsServerConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.dns; import java.util.Set; import org.eclipse.kura.net.IP6Address; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * DNS server configurations for IPv6 networks * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class DnsServerConfigIP6 extends DnsServerConfigIP implements DnsServerConfig6 { public DnsServerConfigIP6(Set forwarders, Set> allowedNetworks) { super(forwarders, allowedNetworks); } @Override public boolean isValid() { // TODO Auto-generated method stub return false; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/dns/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Interfaces for all DNS server instances. * */ package org.eclipse.kura.net.dns; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallAutoNatConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Represents an automatic NAT configuration * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class FirewallAutoNatConfig implements NetConfig { /** The source interface (LAN interface) for the NAT configuration **/ private String sourceInterface; /** The destination interface (WAN interface) for the NAT configuration **/ private String destinationInterface; /** Whether or not MASQUERADE should be enabled **/ private boolean masquerade; /** * Creates a null NAT configuration */ public FirewallAutoNatConfig() { super(); } /** * Creates a complete auto NAT configuration * * @param sourceInterface * The source interface (LAN interface) for the NAT configuration * @param destinationInterface * The destination interface (WAN interface) for the NAT configuration * @param masquerade * Whether or not MASQUERADE should be enabled */ public FirewallAutoNatConfig(String sourceInterface, String destinationInterface, boolean masquerade) { super(); this.sourceInterface = sourceInterface; this.destinationInterface = destinationInterface; this.masquerade = masquerade; } public String getSourceInterface() { return this.sourceInterface; } public void setSourceInterface(String sourceInterface) { this.sourceInterface = sourceInterface; } public String getDestinationInterface() { return this.destinationInterface; } public void setDestinationInterface(String destinationInterface) { this.destinationInterface = destinationInterface; } public boolean isMasquerade() { return this.masquerade; } public void setMasquerade(boolean masquerade) { this.masquerade = masquerade; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.destinationInterface == null ? 0 : this.destinationInterface.hashCode()); result = prime * result + (this.masquerade ? 1231 : 1237); result = prime * result + (this.sourceInterface == null ? 0 : this.sourceInterface.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FirewallAutoNatConfig other = (FirewallAutoNatConfig) obj; if (this.masquerade != other.masquerade) { return false; } if (this.sourceInterface == null) { if (other.sourceInterface != null) { return false; } } else if (!this.sourceInterface.equals(other.sourceInterface)) { return false; } return true; } @Override public boolean isValid() { boolean result = false; if (this.destinationInterface != null && !this.destinationInterface.trim().isEmpty() && this.sourceInterface != null && !this.sourceInterface.trim().isEmpty()) { result = true; } return result; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FirewallNatConfig [m_sourceInterface="); builder.append(this.sourceInterface); builder.append(", m_destinationInterface="); builder.append(this.destinationInterface); builder.append(", m_masquerade="); builder.append(this.masquerade); builder.append("]"); return builder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallNatConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Represents a NAT configuration * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class FirewallNatConfig implements NetConfig { /** The source interface (WAN interface) **/ private final String sourceInterface; /** The destination interface (LAN interface) **/ private final String destinationInterface; /** protocol (i.e. all, tcp, udp) */ private final String protocol; /** source network/host in CIDR notation */ private final String source; /** destination network/host in CIDR notation */ private final String destination; /** Whether or not MASQUERADE should be enabled **/ private final boolean masquerade; /** * Represent the type of the rule * * @since 2.2 */ private final RuleType type; /** * * @deprecated since version 2.2. It will be removed in the next major release. Use instead * {@link #FirewallNatConfig(String, String, String, String, String, boolean, RuleType)} */ @Deprecated public FirewallNatConfig(String srcIface, String dstIface, String protocol, String src, String dst, boolean masquerade) { this.sourceInterface = srcIface; this.destinationInterface = dstIface; this.protocol = protocol; this.source = src; this.destination = dst; this.masquerade = masquerade; this.type = RuleType.GENERIC; } /** * * Create a configuration for a NAT rule * * @param srcIface * the source network interface (WAN interface) * @param dstIface * the destination network interface (LAN interface) * @param protocol * the network protocol (i.e. tcp, udp) * @param src * the source network/host address in CIDR notation * @param dst * the destination network/host address in CIDR notation * @param masquerade * whether or not MASQUERADE should be enabled * @param type * the type of the rule (IP forwarding, Port forwarding or generic) * * @since 2.2 */ public FirewallNatConfig(String srcIface, String dstIface, String protocol, String src, String dst, boolean masquerade, RuleType type) { this.sourceInterface = srcIface; this.destinationInterface = dstIface; this.protocol = protocol; this.source = src; this.destination = dst; this.masquerade = masquerade; this.type = type; } public String getSourceInterface() { return this.sourceInterface; } public String getDestinationInterface() { return this.destinationInterface; } public String getProtocol() { return this.protocol; } public String getSource() { return this.source; } public String getDestination() { return this.destination; } public boolean isMasquerade() { return this.masquerade; } /** * * @since 2.2 */ public RuleType getRuleType() { return this.type; } @Override public boolean isValid() { boolean result = false; if (this.destinationInterface != null && !this.destinationInterface.trim().isEmpty() && this.sourceInterface != null && !this.sourceInterface.trim().isEmpty()) { result = true; } return result; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.destinationInterface == null ? 0 : this.destinationInterface.hashCode()); result = prime * result + (this.sourceInterface == null ? 0 : this.sourceInterface.hashCode()); result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode()); result = prime * result + (this.source == null ? 0 : this.source.hashCode()); result = prime * result + (this.destination == null ? 0 : this.destination.hashCode()); result = prime * result + (this.masquerade ? 1231 : 1237); result = prime * result + (this.type == null ? 0 : this.type.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FirewallNatConfig other = (FirewallNatConfig) obj; if (this.masquerade != other.masquerade) { return false; } if (this.sourceInterface == null) { if (other.sourceInterface != null) { return false; } } else if (!this.sourceInterface.equals(other.sourceInterface)) { return false; } else if (!this.protocol.equals(other.protocol)) { return false; } if (this.destinationInterface == null) { if (other.destinationInterface != null) { return false; } } else if (!this.destinationInterface.equals(other.destinationInterface)) { return false; } if (this.source == null) { if (other.source != null) { return false; } } else if (!this.source.equals(other.source)) { return false; } if (this.destination == null) { if (other.destination != null) { return false; } } else if (!this.destination.equals(other.destination)) { return false; } if (this.type == null) { if (other.type != null) { return false; } } else if (!this.type.equals(other.type)) { return false; } return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FirewallNatConfig [m_sourceInterface="); builder.append(this.sourceInterface); builder.append(", destinationInterface="); builder.append(this.destinationInterface); builder.append(", source="); builder.append(this.source); builder.append(", destination="); builder.append(this.destination); builder.append(", type="); builder.append(this.type); builder.append("]"); return builder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for firewall open port configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface FirewallOpenPortConfig extends NetConfig { /** * Gets the port that is open for inbound connections * * @return The port number representing the inbound network port */ public int getPort(); /** * Gets range of ports that are open for inbound connections * * @return The port range representing the inbound network port */ public String getPortRange(); /** * Gets the type of network protocol (TCP or UDP) that is open for inbound connections * * @return The NetProtocol type associated with this interface */ public NetProtocol getProtocol(); /** * Gets the (optional) permitted remote network that can make inbound connections * * @return The NetworkPair representing the permitted network */ public NetworkPair getPermittedNetwork(); /** * Gets the (optional) permitted remote network that can make inbound connections in CIDR notation (i.e. * 192.168.0.0/24 or 2001:db8::/32) * * @return The NetworkPair representing the permitted network * @since 2.6 */ public String getPermittedNetworkString(); /** * Gets the (optional) permitted MAC address that is allowed to make inbound connections * * @return The MAC address that is allowed to make inbound connections */ public String getPermittedMac(); /** * Gets the (optional) permitted source port range that is allowed to make inbound connections * * @return The source port range that is allowed to make inbound connections */ public String getSourcePortRange(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv4 firewall open port configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface FirewallOpenPortConfig4 extends FirewallOpenPortConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv6 firewall open port configurations * * @noimplement This interface is not intended to be implemented by clients. * @since 2.6 */ @ProviderType public interface FirewallOpenPortConfig6 extends FirewallOpenPortConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import java.util.Objects; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The base class for firewall open port configurations * * @param * the type of IPAddess * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class FirewallOpenPortConfigIP implements FirewallOpenPortConfig { /** The port to open for inbound connections **/ private int port; /** Range of ports to open for inbound connections **/ private String portRange; /** The type of protocol to allow for inbound connections **/ private NetProtocol protocol; /** The (optional) permitted network for inbound connections **/ private NetworkPair permittedNetwork; /** The (optional) permitted interface name for inbound connections **/ private String permittedInterfaceName; /** The (optional) not permitted interface name for inbound connections **/ private String unpermittedInterfaceName; /** The (optional) permitted MAC address for inbound connections **/ private String permittedMac; /** The (options) permitted source port range for inbound connections **/ private String sourcePortRange; /** * Creates and empty open port configuration * * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public FirewallOpenPortConfigIP() { super(); } /** * Creates a complete Open Port configuration * * @param portRange * The range of ports to open for inbound connections * @param protocol * The type of protocol to allow for inbound connections * @param permittedNetwork * The (optional) permitted network for inbound connections * @param permittedInterfaceName * The (optional) permitted interface name for inbound connections * @param unpermittedInterfaceName * The (optional) not permitted interface name for inbound connections * @param permittedMac * The (optional) permitted MAC address for inbound connections * @param sourcePortRange * The (optional) permitted source port range for inbound connections * * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public FirewallOpenPortConfigIP(int port, NetProtocol protocol, NetworkPair permittedNetwork, String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac, String sourcePortRange) { super(); this.port = port; this.portRange = null; this.protocol = protocol; this.permittedNetwork = permittedNetwork; this.permittedInterfaceName = permittedInterfaceName; this.unpermittedInterfaceName = unpermittedInterfaceName; this.permittedMac = permittedMac; this.sourcePortRange = sourcePortRange; } /** * Creates a complete Open Port configuration * * @param port * The port to open for inbound connections * @param protocol * The type of protocol to allow for inbound connections * @param permittedNetwork * The (optional) permitted network for inbound connections * @param permittedInterfaceName * The (optional) permitted interface name for inbound connections * @param unpermittedInterfaceName * The (optional) not permitted interface name for inbound connections * @param permittedMac * The (optional) permitted MAC address for inbound connections * @param sourcePortRange * The (options) permitted source port range for inbound connections * * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public FirewallOpenPortConfigIP(String portRange, NetProtocol protocol, NetworkPair permittedNetwork, String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac, String sourcePortRange) { super(); this.portRange = portRange; this.port = -1; this.protocol = protocol; this.permittedNetwork = permittedNetwork; this.permittedInterfaceName = permittedInterfaceName; this.unpermittedInterfaceName = unpermittedInterfaceName; this.permittedMac = permittedMac; this.sourcePortRange = sourcePortRange; } protected FirewallOpenPortConfigIP(FirewallOpenPortConfigIPBuilder builder) { this.portRange = builder.portRange; this.port = builder.port; this.protocol = builder.protocol; this.permittedNetwork = builder.permittedNetwork; this.permittedInterfaceName = builder.permittedInterfaceName; this.unpermittedInterfaceName = builder.unpermittedInterfaceName; this.permittedMac = builder.permittedMac; this.sourcePortRange = builder.sourcePortRange; } @Override public int getPort() { return this.port; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setPort(int port) { this.port = port; } @Override public String getPortRange() { return this.portRange; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setPortRange(String portRange) { this.portRange = portRange; } @Override public NetProtocol getProtocol() { return this.protocol; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setProtocol(NetProtocol protocol) { this.protocol = protocol; } @Override public NetworkPair getPermittedNetwork() { return this.permittedNetwork; } /** * @since 2.6 */ @Override public String getPermittedNetworkString() { return this.permittedNetwork.getIpAddress().getHostAddress() + "/" + this.permittedNetwork.getPrefix(); } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setPermittedNetwork(NetworkPair permittedNetwork) { this.permittedNetwork = permittedNetwork; } public String getPermittedInterfaceName() { return this.permittedInterfaceName; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setPermittedInterfaceName(String permittedInterfaceName) { this.permittedInterfaceName = permittedInterfaceName; } public String getUnpermittedInterfaceName() { return this.unpermittedInterfaceName; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setUnpermittedInterfaceName(String unpermittedInterfaceName) { this.unpermittedInterfaceName = unpermittedInterfaceName; } @Override public String getPermittedMac() { return this.permittedMac; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setPermittedMac(String permittedMac) { this.permittedMac = permittedMac; } @Override public String getSourcePortRange() { return this.sourcePortRange; } /** * @deprecated since 2.6. Use the FirewallOpenPortConfigIP builder */ @Deprecated public void setSourcePortRange(String sourcePortRange) { this.sourcePortRange = sourcePortRange; } /** * The base builder class for firewall open port configurations * * @since 2.6 */ @ProviderType public abstract static class FirewallOpenPortConfigIPBuilder> { protected int port = -1; protected String portRange; protected NetProtocol protocol; protected NetworkPair permittedNetwork; protected String permittedInterfaceName; protected String unpermittedInterfaceName; protected String permittedMac; protected String sourcePortRange; public T withPort(int port) { this.port = port; return getThis(); } public T withPortRange(String portRange) { this.portRange = portRange; return getThis(); } public T withProtocol(NetProtocol protocol) { this.protocol = protocol; return getThis(); } public T withPermittedNetwork(NetworkPair permittedNetwork) { this.permittedNetwork = permittedNetwork; return getThis(); } public T withPermittedInterfaceName(String permittedInterfaceName) { this.permittedInterfaceName = permittedInterfaceName; return getThis(); } public T withUnpermittedInterfaceName(String unpermittedInterfaceName) { this.unpermittedInterfaceName = unpermittedInterfaceName; return getThis(); } public T withPermittedMac(String permittedMac) { this.permittedMac = permittedMac; return getThis(); } public T withSourcePortRange(String sourcePortRange) { this.sourcePortRange = sourcePortRange; return getThis(); } public abstract T getThis(); public abstract FirewallOpenPortConfigIP build() throws UnknownHostException; } @Override public int hashCode() { return Objects.hash(permittedInterfaceName, permittedMac, permittedNetwork, port, portRange, protocol, sourcePortRange, unpermittedInterfaceName); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FirewallOpenPortConfigIP other = (FirewallOpenPortConfigIP) obj; return Objects.equals(permittedInterfaceName, other.permittedInterfaceName) && Objects.equals(permittedMac, other.permittedMac) && Objects.equals(permittedNetwork, other.permittedNetwork) && port == other.port && Objects.equals(portRange, other.portRange) && protocol == other.protocol && Objects.equals(sourcePortRange, other.sourcePortRange) && Objects.equals(unpermittedInterfaceName, other.unpermittedInterfaceName); } @Override public boolean isValid() { if (this.port < 0 || this.port > 65535) { return false; } if (this.protocol == null || !this.protocol.equals(NetProtocol.tcp) || !this.protocol.equals(NetProtocol.udp)) { return false; } // TODO - add checks for optional parameters to make sure if they are not null they are valid return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FirewallOpenPortConfigIP [port="); builder.append(this.port); builder.append(", portRange="); builder.append(this.portRange); builder.append(", protocol="); builder.append(this.protocol); builder.append(", permittedNetwork="); builder.append(this.permittedNetwork); builder.append(", permittedMac="); builder.append(this.permittedMac); builder.append(", sourcePortRange="); builder.append(this.sourcePortRange); builder.append("]"); return builder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The implementation of IPv4 firewall open port configurations * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class FirewallOpenPortConfigIP4 extends FirewallOpenPortConfigIP implements FirewallOpenPortConfig4 { /** * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()} */ @Deprecated public FirewallOpenPortConfigIP4() { super(); } /** * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()} */ @Deprecated public FirewallOpenPortConfigIP4(int port, NetProtocol protocol, NetworkPair permittedNetwork, String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac, String sourcePortRange) { super(port, protocol, permittedNetwork, permittedInterfaceName, unpermittedInterfaceName, permittedMac, sourcePortRange); } /** * @deprecated since 2.6. Use {@link FirewallOpenPortConfigIP4.builder()} */ @Deprecated public FirewallOpenPortConfigIP4(String portRange, NetProtocol protocol, NetworkPair permittedNetwork, String permittedInterfaceName, String unpermittedInterfaceName, String permittedMac, String sourcePortRange) { super(portRange, protocol, permittedNetwork, permittedInterfaceName, unpermittedInterfaceName, permittedMac, sourcePortRange); } private FirewallOpenPortConfigIP4(FirewallOpenPortConfigIP4Builder builder) { super(builder); } /** * Return the builder for the IPv4 firewall open port configuration * * @since 2.6 */ public static FirewallOpenPortConfigIP4Builder builder() { return new FirewallOpenPortConfigIP4Builder(); } /** * The builder class for the IPv4 firewall open port configuration * * @since 2.6 */ @ProviderType public static class FirewallOpenPortConfigIP4Builder extends FirewallOpenPortConfigIPBuilder { /** * Builds a new IPv4 firewall open port configuration */ @Override public FirewallOpenPortConfigIP4 build() throws UnknownHostException { if (this.permittedNetwork == null) { this.withPermittedNetwork(new NetworkPair<>(IP4Address.getDefaultAddress(), (short) 0)); } return new FirewallOpenPortConfigIP4(this); } @Override public FirewallOpenPortConfigIP4Builder getThis() { return this; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallOpenPortConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import org.eclipse.kura.net.IP6Address; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The implementation of IPv6 firewall open port configurations * * @noextend This class is not intended to be subclassed by clients. * @since 2.6 */ @ProviderType public class FirewallOpenPortConfigIP6 extends FirewallOpenPortConfigIP implements FirewallOpenPortConfig6 { private FirewallOpenPortConfigIP6(FirewallOpenPortConfigIP6Builder builder) { super(builder); } public static FirewallOpenPortConfigIP6Builder builder() { return new FirewallOpenPortConfigIP6Builder(); } /** * The builder class for the IPv6 firewall open port configuration */ @ProviderType public static class FirewallOpenPortConfigIP6Builder extends FirewallOpenPortConfigIPBuilder { /** * Builds a new IPv6 firewall open port configuration */ @Override public FirewallOpenPortConfigIP6 build() throws UnknownHostException { if (this.permittedNetwork == null) { this.withPermittedNetwork(new NetworkPair<>(IP6Address.getDefaultAddress(), (short) 0)); } return new FirewallOpenPortConfigIP6(this); } @Override public FirewallOpenPortConfigIP6Builder getThis() { return this; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for firewall port forward configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface FirewallPortForwardConfig extends NetConfig { /** * The external (WAN) interface to listen for inbound connections on * * @return The interface name used for this port forward configuration */ public String getInboundInterface(); /** * The internal (LAN) interface packets will be forwarded to * * @return The interface name used for this port forward configuration */ public String getOutboundInterface(); /** * The LAN IP address to forward connections to * * @return The LAN IPAddress to forward connections to * @deprecated since 2.6. Use {@link FirewallPortForwardConfig#getIPAddress} */ @Deprecated public IP4Address getAddress(); /** * The LAN IP address to forward connections to * * @return The LAN IPAddress to forward connections to * @since 2.6 */ public IPAddress getIPAddress(); /** * The netmask of the LAN IP address to forward connections to * * @return The netmask of the LAN IPAddress to forward connections to * @since 2.6 */ public short getIPAddressNetmask(); /** * Gets the type of network protocol (TCP or UDP) that is used for this configuration * * @return The NetProtocol type associated with this interface */ public NetProtocol getProtocol(); /** * The inbound (WAN) port to use for this configuration * * @return The WAN port number */ public int getInPort(); /** * The outbound (LAN) port to use for this configuration * * @return The LAN port number */ public int getOutPort(); /** * Use masquerading * * @return boolean */ public boolean isMasquerade(); /** * Gets the (optional) permitted remote network that can make inbound connections * * @return The NetworkPair representing the permitted network */ public NetworkPair getPermittedNetwork(); /** * Gets the (optional) permitted MAC address that is allowed to make inbound connections * * @return The MAC address that is allowed to make inbound connections */ public String getPermittedMac(); /** * Gets the (optional) permitted source port range that is allowed to make inbound connections * * @return The source port range that is allowed to make inbound connections */ public String getSourcePortRange(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv4 firewall port forward configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface FirewallPortForwardConfig4 extends FirewallPortForwardConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv6 firewall port forward configurations * * @noimplement This interface is not intended to be implemented by clients. * @since 2.6 */ @ProviderType public interface FirewallPortForwardConfig6 extends FirewallPortForwardConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The base class for firewall port forward configurations * * @param * the type of IPAddess * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class FirewallPortForwardConfigIP implements FirewallPortForwardConfig { /** The interface name on which this configuration will listen for inbound connections **/ private String inboundIface; /** The interface name on which packet will be forwarded */ private String outboundIface; /** The LAN address to forward to **/ private T address; /** The protocol (TCP or UDP) to listen for and forward **/ private NetProtocol protocol; /** The inbound (WAN) port to listen on **/ private int inPort; /** The outbound (LAN) port to listen on **/ private int outPort; /** use masquerading */ private boolean masquerade; /** The (optional) permitted network for inbound connections **/ private NetworkPair permittedNetwork; /** The (optional) permitted MAC address for inbound connections **/ private String permittedMac; /** The (options) permitted source port range for inbound connections **/ private String sourcePortRange; /** * Creates and empty port forward configuration * * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public FirewallPortForwardConfigIP() { super(); } /** * Creates a complete port forward configuration * * @param inboundIface * The interface name on which this configuration will listen for inbound connections * @param outboundIface * The inetrface name on which packet will be forwarded * @param address * The LAN address to forward to * @param protocol * The protocol (TCP or UDP) to listen for and forward * @param inPort * The inbound (WAN) port to listen on * @param outPort * The outbound (LAN) port to listen on * @param masquerade * Use masquerade * @param permittedNetwork * The (optional) permitted network for inbound connections * @param permittedMac * The (optional) permitted MAC address for inbound connections * @param sourcePortRange * The (options) permitted source port range for inbound connections * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @SuppressWarnings("checkstyle:parameterNumber") @Deprecated public FirewallPortForwardConfigIP(String inboundIface, String outboundIface, IP4Address address, NetProtocol protocol, int inPort, int outPort, boolean masquerade, NetworkPair permittedNetwork, String permittedMac, String sourcePortRange) { super(); this.inboundIface = inboundIface; this.outboundIface = outboundIface; this.address = (T) address; this.protocol = protocol; this.inPort = inPort; this.outPort = outPort; this.masquerade = masquerade; this.permittedNetwork = permittedNetwork; this.permittedMac = permittedMac; this.sourcePortRange = sourcePortRange; } protected FirewallPortForwardConfigIP(FirewallPortForwardConfigIPBuilder builder) { this.inboundIface = builder.inboundIface; this.outboundIface = builder.outboundIface; this.address = builder.address; this.protocol = builder.protocol; this.inPort = builder.inPort; this.outPort = builder.outPort; this.masquerade = builder.masquerade; this.permittedNetwork = builder.permittedNetwork; this.permittedMac = builder.permittedMac; this.sourcePortRange = builder.sourcePortRange; } @Override public String getInboundInterface() { return this.inboundIface; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setInboundInterface(String interfaceName) { this.inboundIface = interfaceName; } @Override public String getOutboundInterface() { return this.outboundIface; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setOutboundInterface(String interfaceName) { this.outboundIface = interfaceName; } /** * @deprecated since 2.6. Use {@link getIPAddress} */ @Override @Deprecated public IP4Address getAddress() { return (IP4Address) this.address; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setAddress(IP4Address address) { this.address = (T) address; } /** * @since 2.6 */ @Override public T getIPAddress() { return this.address; } @Override public NetProtocol getProtocol() { return this.protocol; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setProtocol(NetProtocol protocol) { this.protocol = protocol; } @Override public int getInPort() { return this.inPort; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setInPort(int inPort) { this.inPort = inPort; } @Override public int getOutPort() { return this.outPort; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setOutPort(int outPort) { this.outPort = outPort; } @Override public boolean isMasquerade() { return this.masquerade; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setMasquerade(boolean masquerade) { this.masquerade = masquerade; } @Override public NetworkPair getPermittedNetwork() { return this.permittedNetwork; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setPermittedNetwork(NetworkPair permittedNetwork) { this.permittedNetwork = permittedNetwork; } @Override public String getPermittedMac() { return this.permittedMac; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setPermittedMac(String permittedMac) { this.permittedMac = permittedMac; } @Override public String getSourcePortRange() { return this.sourcePortRange; } /** * @deprecated since 2.6. Use the FirewallPortForwardConfigIP builder */ @Deprecated public void setSourcePortRange(String sourcePortRange) { this.sourcePortRange = sourcePortRange; } /** * The base builder class for firewall port forward configurations * * @since 2.6 */ @ProviderType public abstract static class FirewallPortForwardConfigIPBuilder> { protected String inboundIface; protected String outboundIface; protected U address; protected NetProtocol protocol; protected int inPort; protected int outPort; protected boolean masquerade = false; protected NetworkPair permittedNetwork; protected String permittedMac; protected String sourcePortRange; public T withInboundIface(String inboundIface) { this.inboundIface = inboundIface; return getThis(); } public T withOutboundIface(String outboundIface) { this.outboundIface = outboundIface; return getThis(); } public T withAddress(U address) { this.address = address; return getThis(); } public T withProtocol(NetProtocol protocol) { this.protocol = protocol; return getThis(); } public T withInPort(int inPort) { this.inPort = inPort; return getThis(); } public T withOutPort(int outPort) { this.outPort = outPort; return getThis(); } public T withMasquerade(boolean masquerade) { this.masquerade = masquerade; return getThis(); } public T withPermittedNetwork(NetworkPair permittedNetwork) { this.permittedNetwork = permittedNetwork; return getThis(); } public T withPermittedMac(String permittedMac) { this.permittedMac = permittedMac; return getThis(); } public T withSourcePortRange(String sourcePortRange) { this.sourcePortRange = sourcePortRange; return getThis(); } public abstract T getThis(); public abstract FirewallPortForwardConfigIP build() throws UnknownHostException; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.address == null ? 0 : this.address.hashCode()); result = prime * result + this.inPort; result = prime * result + (this.inboundIface == null ? 0 : this.inboundIface.hashCode()); result = prime * result + (this.outboundIface == null ? 0 : this.outboundIface.hashCode()); result = prime * result + (this.masquerade ? 1231 : 1237); result = prime * result + this.outPort; result = prime * result + (this.permittedMac == null ? 0 : this.permittedMac.hashCode()); result = prime * result + (this.permittedNetwork == null ? 0 : this.permittedNetwork.hashCode()); result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode()); result = prime * result + (this.sourcePortRange == null ? 0 : this.sourcePortRange.hashCode()); return result; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("FirewallPortForwardConfigIP [inboundIface="); builder.append(this.inboundIface); builder.append(", outboundIface="); builder.append(this.outboundIface); builder.append(", address="); builder.append(this.address); builder.append(", protocol="); builder.append(this.protocol); builder.append(", inPort="); builder.append(this.inPort); builder.append(", outPort="); builder.append(this.outPort); builder.append(", permittedNetwork="); builder.append(this.permittedNetwork); builder.append(", permittedMac="); builder.append(this.permittedMac); builder.append(", sourcePortRange="); builder.append(this.sourcePortRange); builder.append("]"); return builder.toString(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } @SuppressWarnings("rawtypes") FirewallPortForwardConfigIP other = (FirewallPortForwardConfigIP) obj; if (this.address == null) { if (other.address != null) { return false; } } else if (!this.address.equals(other.address)) { return false; } if (this.inPort != other.inPort) { return false; } if (this.inboundIface == null) { if (other.inboundIface != null) { return false; } } else if (!this.inboundIface.equals(other.inboundIface)) { return false; } if (this.outboundIface == null) { if (other.outboundIface != null) { return false; } } else if (!this.outboundIface.equals(other.outboundIface)) { return false; } if (this.outPort != other.outPort) { return false; } if (this.masquerade != other.masquerade) { return false; } if (this.permittedMac == null) { if (other.permittedMac != null) { return false; } } else if (!this.permittedMac.equals(other.permittedMac)) { return false; } if (this.permittedNetwork == null) { if (other.permittedNetwork != null) { return false; } } else if (!this.permittedNetwork.equals(other.permittedNetwork)) { return false; } if (this.protocol != other.protocol) { return false; } if (this.sourcePortRange == null) { if (other.sourcePortRange != null) { return false; } } else if (!this.sourcePortRange.equals(other.sourcePortRange)) { return false; } return true; } @Override public boolean isValid() { if (this.inboundIface == null || this.inboundIface.trim().isEmpty()) { return false; } if (this.outboundIface == null || this.outboundIface.trim().isEmpty()) { return false; } if (this.address == null) { return false; } if (this.inPort < 0 || this.inPort > 65535 || this.outPort < 0 || this.outPort > 65535) { return false; } if (this.protocol == null || !this.protocol.equals(NetProtocol.tcp) || !this.protocol.equals(NetProtocol.udp)) { return false; } // TODO - add checks for optional parameters to make sure if they are not null they are valid return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.NetProtocol; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The class for IPv4 firewall port forward configurations * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class FirewallPortForwardConfigIP4 extends FirewallPortForwardConfigIP implements FirewallPortForwardConfig4 { /** * @deprecated since 2.6. Use {@link FirewallPortForwardConfigIP4.builder()} */ @Deprecated public FirewallPortForwardConfigIP4() { super(); } /** * @deprecated since 2.6. Use {@link FirewallPortForwardConfigIP4.builder()} */ @SuppressWarnings("checkstyle:parameterNumber") @Deprecated public FirewallPortForwardConfigIP4(String inboundIface, String outboundIface, IP4Address address, NetProtocol protocol, int inPort, int outPort, boolean masquerade, NetworkPair permittedNetwork, String permittedMac, String sourcePortRange) { super(inboundIface, outboundIface, address, protocol, inPort, outPort, masquerade, permittedNetwork, permittedMac, sourcePortRange); } private FirewallPortForwardConfigIP4(FirewallPortForwardConfigIP4Builder builder) { super(builder); } /** * Return the builder for the IPv4 firewall port forward configuration * * @since 2.6 */ public static FirewallPortForwardConfigIP4Builder builder() { return new FirewallPortForwardConfigIP4Builder(); } /** * @since 2.6 */ @Override public short getIPAddressNetmask() { return (short) 32; } /** * The builder class for the IPv4 firewall port forward configuration * * @since 2.6 */ @ProviderType public static class FirewallPortForwardConfigIP4Builder extends FirewallPortForwardConfigIPBuilder { /** * Builds a new IPv4 firewall port forward configuration */ @Override public FirewallPortForwardConfigIP4 build() throws UnknownHostException { if (this.permittedNetwork == null) { this.withPermittedNetwork(new NetworkPair<>(IP4Address.getDefaultAddress(), (short) 0)); } return new FirewallPortForwardConfigIP4(this); } @Override public FirewallPortForwardConfigIP4Builder getThis() { return this; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/FirewallPortForwardConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; import java.net.UnknownHostException; import org.eclipse.kura.net.IP6Address; import org.eclipse.kura.net.NetworkPair; import org.osgi.annotation.versioning.ProviderType; /** * The implementation of IPv6 firewall port forward configurations * * @noextend This class is not intended to be subclassed by clients. * @since 2.6 */ @ProviderType public class FirewallPortForwardConfigIP6 extends FirewallPortForwardConfigIP implements FirewallPortForwardConfig6 { private FirewallPortForwardConfigIP6(FirewallPortForwardConfigIP6Builder builder) { super(builder); } public static FirewallPortForwardConfigIP6Builder builder() { return new FirewallPortForwardConfigIP6Builder(); } /** * @since 2.6 */ @Override public short getIPAddressNetmask() { return (short) 128; } /** * The builder class for the IPv6 firewall port forward configuration */ @ProviderType public static class FirewallPortForwardConfigIP6Builder extends FirewallPortForwardConfigIPBuilder { /** * Builds a new IPv6 firewall port forward configuration */ @Override public FirewallPortForwardConfigIP6 build() throws UnknownHostException { if (this.permittedNetwork == null) { this.withPermittedNetwork(new NetworkPair<>(IP6Address.getDefaultAddress(), (short) 0)); } return new FirewallPortForwardConfigIP6(this); } @Override public FirewallPortForwardConfigIP6Builder getThis() { return this; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/RuleType.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.firewall; /** * Represents the type of NAT rule * * @since 2.2 */ public enum RuleType { PORT_FORWARDING, IP_FORWARDING, GENERIC; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/firewall/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Interfaces firewall configuration instances. * */ package org.eclipse.kura.net.firewall; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/CellularModem.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Sterwen-Technology ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.List; import org.eclipse.kura.KuraException; import org.eclipse.kura.comm.CommURI; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface CellularModem { public enum SerialPortType { DATAPORT, ATPORT, GPSPORT } /** * Reports modem's model * * @return model, null if not known */ public String getModel() throws KuraException; /** * Returns modem's manufacturer identification * * @return manufacturer, null if not known */ public String getManufacturer() throws KuraException; /** * Answers modem's serial number (IMEI/MEID/ESN) * * @return serial number, null if not known * @throws KuraException */ public String getSerialNumber() throws KuraException; /** * Answers International Mobile Subscribe Identity (IMSI) * * @return IMSI number, null if not known * @throws KuraException * * @deprecated since 2.4. Use {@link getMobileSubscriberIdentity(boolean * recompute)} instead. */ @Deprecated public String getMobileSubscriberIdentity() throws KuraException; /** * Answers Integrated Circuit Card Identification (ICCID) * * @return ICCID, "N/A" if not applicable * @throws KuraException * * @deprecated since 2.4. Use {@link getIntegratedCirquitCardId(boolean * recompute)} instead. */ @Deprecated public String getIntegratedCirquitCardId() throws KuraException; /** * Reports modem's revision identification * * @return revision ID, null if not known */ public String getRevisionID() throws KuraException; /** * Reports if Modem replies to the 'AT' command * * @return 'true' if AT reachable, 'false' otherwise * @throws KuraException */ public boolean isReachable() throws KuraException; /** * Reports if specified port can be opened * * @param port * - modem's serial port * @return 'true' if port can be opened, 'false' otherwise */ public boolean isPortReachable(String port); /** * resets the modem and tries to restore the state * of the modem driver. (e.g. PPP connection, status thread) * * @throws KuraException */ public void reset() throws KuraException; /** * Reports signal strength in dBm * * @throws KuraException * @return signal strength * * @deprecated since 2.4. Use {@link getSignalStrength(boolean recompute)} * instead. */ @Deprecated public int getSignalStrength() throws KuraException; /** * Reports modem registration status * * @throws KuraException * @return modem registration status as {@link ModemRegistrationStatus} * * @deprecated since 2.4. Use {@link getRegistrationStatus(boolean recompute)} * instead. */ @Deprecated public ModemRegistrationStatus getRegistrationStatus() throws KuraException; /** * Reports number of bytes transmitted during a call * * @return number of bytes transmitted * @throws KuraException */ public long getCallTxCounter() throws KuraException; /** * Reports number of bytes received during a call * * @return number of bytes received * @throws KuraException */ public long getCallRxCounter() throws KuraException; /** * Reports Service Type * * @throws KuraException * @return service indication */ public String getServiceType() throws KuraException; /** * Returns the associated UsbModemDevice * * @return UsbModemDevice */ public ModemDevice getModemDevice(); /** * @since 2.4 */ public String getLAC() throws KuraException; /** * @since 2.4 */ public String getCI() throws KuraException; /** * @since 2.4 */ public String getPLMNID() throws KuraException; /** * @since 2.4 */ public String getBand() throws KuraException; /** * @since 2.4 */ public String getNetworkName() throws KuraException; /** * @since 2.4 */ public String getRadio() throws KuraException; public String getDataPort() throws KuraException; public String getAtPort() throws KuraException; public String getGpsPort() throws KuraException; public CommURI getSerialConnectionProperties(SerialPortType portType) throws KuraException; public boolean isGpsSupported() throws KuraException; public boolean isGpsEnabled(); public void enableGps() throws KuraException; public void disableGps() throws KuraException; /** * @since 2.2 */ public boolean hasDiversityAntenna(); /** * @since 2.2 */ public boolean isDiversityEnabled(); /** * @since 2.2 */ public void enableDiversity() throws KuraException; /** * @since 2.2 */ public void disableDiversity() throws KuraException; public List getConfiguration(); public void setConfiguration(List netConfigs); public List getTechnologyTypes() throws KuraException; /** * @since 1.4 */ public List getPdpContextInfo() throws KuraException; /** * Return the firmware version of the modem module * * @return a string representing the firmware version * * @since 2.3 */ public String getFirmwareVersion() throws KuraException; /** * Reports signal strength in dBm * * @param recompute: * if true the value is recomputed. Otherwise, a cached value * is returned * @return an integer representing the rssi * @throws KuraException * * @since 2.4 */ public int getSignalStrength(boolean recompute) throws KuraException; /** * Reports modem registration status * * @param recompute: * if true the value is recomputed. Otherwise, a cached value * is returned * @throws KuraException * @return modem registration status as {@link ModemRegistrationStatus} * * @since 2.4 */ public ModemRegistrationStatus getRegistrationStatus(boolean recompute) throws KuraException; /** * Answers International Mobile Subscribe Identity (IMSI) * * @param recompute: * if true the value is recomputed. Otherwise, a cached value * is returned * @return IMSI number, null if not known * @throws KuraException * * @since 2.4 */ public String getMobileSubscriberIdentity(boolean recompute) throws KuraException; /** * Answers Integrated Circuit Card Identification (ICCID) * * @param recompute: * if true the value is recomputed. Otherwise, a cached value * is returned * @return ICCID, "N/A" if not applicable * @throws KuraException * * @since 2.4 */ public String getIntegratedCirquitCardId(boolean recompute) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemAddedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Emitted when a modem is inserted into the gateway * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ModemAddedEvent extends Event { /** Topic of the ModemAddedEvent */ public static final String MODEM_EVENT_ADDED_TOPIC = "org/eclipse/kura/net/modem/ADDED"; ModemDevice modemDevice; public ModemAddedEvent(ModemDevice modemDevice) { super(MODEM_EVENT_ADDED_TOPIC, (Map) null); this.modemDevice = modemDevice; } public ModemDevice getModemDevice() { return this.modemDevice; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemCdmaServiceProvider.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; /** * @deprecated since 3.0 */ @Deprecated public enum ModemCdmaServiceProvider { UNKNOWN(0), SPRINT(1), AERIS(2), VERIZON(3); private int provider; private ModemCdmaServiceProvider(int provider) { this.provider = provider; } public int getProvider() { return this.provider; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Arrays; import java.util.Objects; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Modem configuration representation * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ModemConfig implements NetConfig { /** * Configuration for a cellular modem. */ public enum PdpType { IP, PPP, IPv6, UNKNOWN } public enum AuthType { NONE, AUTO, PAP, CHAP } private boolean enabled = false; private String dialString = ""; private int pppNumber = 0; private int profileID = 0; private PdpType pdpType = PdpType.IP; private AuthType authType = AuthType.NONE; private String apn = ""; private String username = ""; private Password password = new Password(""); private boolean persist = false; private int holdoff = 1; private int maxFail = 0; private int idle = 0; private String activeFilter = ""; private int lcpEchoInterval = 0; private int lcpEchoFailure = 0; private IPAddress ipAddress = null; private int dataCompression = 0; // FIXME: change to enum? private int headerCompression = 0; // FIXME: change to enum? private boolean gpsEnabled = false; private boolean diversityEnabled = false; private int resetTimeout = 0; /** * Empty constructor */ public ModemConfig() { } /** * PDP config constructor * * @param apn * - access point name as {@link String} * @param ipAddress * - IP address as {@link String} * @param profileID * - PDP profile ID as {@link int} * @param pdpType * - PDP type as {@link PdpType} * @param dataCompression * - PDP data compression as {@link int} * @param headerCompresion * - PDP header compression as {@link int} */ public ModemConfig(int profileID, PdpType pdpType, String apn, IPAddress ipAddress, int dataCompression, int headerCompresion) { this.profileID = profileID; this.pdpType = pdpType; this.apn = apn; this.ipAddress = ipAddress; this.dataCompression = dataCompression; this.headerCompression = headerCompresion; } /** * Reports whether it is enabled. * * @return is enabled as {@link boolean} */ public boolean isEnabled() { return this.enabled; } /** * Sets the enabled setting. * * @param enabled * - enabled status as {@link boolean} */ public void setEnabled(boolean enabled) { this.enabled = enabled; } /** * Gets the dial string. * * @return dial string as {@link String} */ public String getDialString() { return this.dialString; } /** * Sets the dial string. * * @param dialString * - dial string as {@link String} */ public void setDialString(String dialString) { this.dialString = dialString; } /** * Reports authentication type. * * @return authentication type as {@link AuthType} */ public AuthType getAuthType() { return this.authType; } /** * Sets authentication type. * * @param authType * - authentication type as {@link AuthType} */ public void setAuthType(AuthType authType) { this.authType = authType; } /** * Reports user name. * * @return user name as {@link String} */ public String getUsername() { return this.username; } /** * Sets user name. * * @param username * - user name as {@link String} */ public void setUsername(String username) { this.username = username; } /** * Reports password. * * @return password as {@link String} * @deprecated */ @Deprecated public String getPassword() { return this.password.toString(); } /** * Reports password. * * @return password as {@link Password} * @since 1.3 */ public Password getPasswordAsPassword() { return this.password; } /** * Sets password. * * @param password * - password as {@link String} */ public void setPassword(String password) { this.password = new Password(password); } /** * Sets password. * * @param password * - password as {@link Password} * @since 1.3 */ public void setPassword(Password password) { this.password = password; } /** * Reports if pppd is instructed to exit after a connection is terminated. * * @return 'persist' flag {@link boolean} */ public boolean isPersist() { return this.persist; } /** * Sets 'persist' flag to instruct pppd if it needs to exit after a connection is terminated. * * @param persist * as {@link boolean} */ public void setPersist(boolean persist) { this.persist = persist; } /** * Returns the 'holdoff' parameter that instruct pppd on how many seconds to wait before re-initiating the link * after it terminates. This option only has any effect if the persist or demand option is used. The holdoff period * is not * applied if the link was terminated because it was idle. * * @return 'holdoff' parameter {@link integer} * @since 2.5 */ public int getHoldoff() { return this.holdoff; } /** * Sets 'holdoff' parameter to instruct pppd on how many seconds to wait before re-initiating the link after it * terminates. This option only has any effect if the persist or demand option is used. The holdoff period is not * applied if the link was terminated because it was idle. * * @param holdoff * as {@link integer} * @since 2.5 */ public void setHoldoff(int holdoff) { this.holdoff = holdoff; } /** * Reports maximum number of failed connection attempts. * * @return maximum number of failed connection attempts as {@link int} */ public int getMaxFail() { return this.maxFail; } /** * Sets maximum number of failed connection attempts * * @param maxFail * - maximum number of failed connection attempts as {@link int} */ public void setMaxFail(int maxFail) { this.maxFail = maxFail; } /** * Reports value of the 'idle' option. * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds. * * @return value of the 'idle' option as {@link int} * @deprecated since 3.0 */ @Deprecated public int getIdle() { return this.idle; } /** * Sets value of the 'idle' option. * The 'idle' option specifies that pppd should disconnect if the link is idle for n seconds. * * @param idle * @deprecated since 3.0 */ @Deprecated public void setIdle(int idle) { this.idle = idle; } /** * Reports the value of the 'active-filter' option that specifies a packet filter to be * applied to data packets to determine which packets are to be regarded as link activity. * * @return value of the 'active-filter' option as {@link String} * @deprecated since 3.0 */ @Deprecated public String getActiveFilter() { return this.activeFilter; } /** * Sets the value of the 'active-filter' option that specifies a packet filter to be * applied to data packets to determine which packets are to be regarded as link activity. * * @param activeFilter * - active filter as {@link String} * @deprecated since 3.0 */ @Deprecated public void setActiveFilter(String activeFilter) { this.activeFilter = activeFilter; } /** * Reports LCP echo interval * * @return LCP echo interval (in sec) as {@link int} */ public int getLcpEchoInterval() { return this.lcpEchoInterval; } /** * Sets LCP echo interval * * @param lcpEchoInterval * - LCP Echo interval as {@link int} */ public void setLcpEchoInterval(int lcpEchoInterval) { this.lcpEchoInterval = lcpEchoInterval; } /** * Reports number of failed LCP echo requests * * @return number of failed LCP echo requests as {@link int} */ public int getLcpEchoFailure() { return this.lcpEchoFailure; } /** * Sets number of failed LCP echo requests * (unacknowledged LCP echo requests to be sent for pppd to presume the peer to be dead) * * @param lcpEchoFailure */ public void setLcpEchoFailure(int lcpEchoFailure) { this.lcpEchoFailure = lcpEchoFailure; } /** * Reports PPP number (i.e. '0' for ppp0). * * @return PPP number as {@link int} */ public int getPppNumber() { return this.pppNumber; } /** * Sets PPP number (i.e. '0' for ppp0). * * @param pppNumber * - PPP number as {@link int} */ public void setPppNumber(int pppNumber) { this.pppNumber = pppNumber; } /** * Reports PDP profile ID. * * @return PDP profile ID as {@link int} */ public int getProfileID() { return this.profileID; } /** * Sets PDP profile ID. * * @param id * - PDP profile ID as {@link int} */ public void setProfileID(int id) { this.profileID = id; } /** * Reports PDP type. * * @return PDP type as {@link PdpType} */ public PdpType getPdpType() { return this.pdpType; } /** * Sets PDP type. * * @param pdpType * - PDP type as {@link PdpType} */ public void setPdpType(PdpType pdpType) { this.pdpType = pdpType; } /** * Reports access point name. * * @return access point name as {@link String} */ public String getApn() { return this.apn; } /** * Sets access point name. * * @param apn * - access point name as {@link String} */ public void setApn(String apn) { this.apn = apn; } /** * Reports PDP IP address. * * @return IP address as {@link IPAddress} */ public IPAddress getIpAddress() { return this.ipAddress; } /** * Sets PDP IP address. * * @param address * - IP address as {@link IPAddress} */ public void setIpAddress(IPAddress address) { this.ipAddress = address; } /** * Reports a value of numeric parameter that supports PDP data compression. * * @return PDP data compression as {@link int} */ public int getDataCompression() { return this.dataCompression; } /** * Sets a value of numeric parameter that supports PDP data compression. * * @param dataCompression * - PDP data compression as {@link int} */ public void setDataCompression(int dataCompression) { this.dataCompression = dataCompression; } /** * Reports a value of numeric parameter that supports PDP header compression. * * @return PDP header compression as {@link int} */ public int getHeaderCompression() { return this.headerCompression; } /** * Sets a value of numeric parameter that supports PDP header compression. * * @param headerCompression * headerCompression PDP header compression as {@link int} */ public void setHeaderCompression(int headerCompression) { this.headerCompression = headerCompression; } /** * Reports if PDP data compression is enabled. * * @return {@link boolean} */ public boolean isDataCompression() { return this.dataCompression == 0 ? false : true; } /** * Reports if PDP header compression is enabled. * * @return {@link boolean} */ public boolean isHeaderCompression() { return this.headerCompression == 0 ? false : true; } public boolean isGpsEnabled() { return this.gpsEnabled; } public int getResetTimeout() { return this.resetTimeout; } public void setResetTimeout(int tout) { this.resetTimeout = tout; } public void setGpsEnabled(boolean gpsEnabled) { this.gpsEnabled = gpsEnabled; } /** * @since 2.2 */ public boolean isDiversityEnabled() { return this.diversityEnabled; } /** * @since 2.2 */ public void setDiversityEnabled(boolean diversityEnabled) { this.diversityEnabled = diversityEnabled; } @Override public int hashCode() { return Objects.hash(this.activeFilter, this.apn, this.authType, this.dataCompression, this.dialString, this.diversityEnabled, this.enabled, this.gpsEnabled, this.headerCompression, this.holdoff, this.idle, this.ipAddress, this.lcpEchoFailure, this.lcpEchoInterval, this.maxFail, this.password, this.pdpType, this.persist, this.pppNumber, this.profileID, this.resetTimeout, this.username); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof ModemConfig)) { return false; } ModemConfig other = (ModemConfig) obj; return Objects.equals(this.activeFilter, other.activeFilter) && Objects.equals(this.apn, other.apn) && this.authType == other.authType && this.dataCompression == other.dataCompression && Objects.equals(this.dialString, other.dialString) && this.diversityEnabled == other.diversityEnabled && this.enabled == other.enabled && this.gpsEnabled == other.gpsEnabled && this.headerCompression == other.headerCompression && this.holdoff == other.holdoff && this.idle == other.idle && Objects.equals(this.ipAddress, other.ipAddress) && this.lcpEchoFailure == other.lcpEchoFailure && this.lcpEchoInterval == other.lcpEchoInterval && this.maxFail == other.maxFail && Arrays.equals(this.password.getPassword(), other.getPasswordAsPassword().getPassword()) && this.pdpType == other.pdpType && this.persist == other.persist && this.pppNumber == other.pppNumber && this.profileID == other.profileID && this.resetTimeout == other.resetTimeout && Objects.equals(this.username, other.username); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(super.toString()); sb.append("ModemConfig - "); sb.append("Enabled: ").append(this.enabled); sb.append(" - PPP Number: ").append(this.pppNumber); sb.append(" - Dial String: ").append(this.dialString); sb.append(" - Profile ID: ").append(this.profileID); sb.append(" - PDP Type: ").append(this.pdpType); sb.append(" - Auth Type: ").append(this.authType); sb.append(" - APN: ").append(this.apn); sb.append(" - Username: ").append(this.username); sb.append(" - Password: ").append(this.password); sb.append(" - IP Address: ").append(this.ipAddress == null ? "null" : this.ipAddress.getHostAddress()); sb.append(" - Data Compression: ").append(this.dataCompression); sb.append(" - Header Compression: ").append(this.headerCompression); return sb.toString(); } @Override public boolean isValid() { boolean result = true; if (this.pppNumber < 0) { result = false; } return result; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConnectionStatus.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; public enum ModemConnectionStatus { /** UNKNOWN **/ UNKNOWN, /** DISCONNECTED **/ DISCONNECTED, /** CONNECTING **/ CONNECTING, /** CONNECTED **/ CONNECTED } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemConnectionType.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; public enum ModemConnectionType { /** Point to Point Protocol **/ PPP, /** Direct IP **/ DirectIP } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ModemDevice { /** * The list of serial ports available on the device * * @return a list of serial ports names */ public List getSerialPorts(); /** * The manufacturer name of the device * * @return The manufacturer name of the device */ public String getManufacturerName(); /** * The product name of the device * * @return The product name of the device */ public String getProductName(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemGpsDisabledEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ModemGpsDisabledEvent extends Event { /** Topic of the ModemGpsDisabledEvent */ public static final String MODEM_EVENT_GPS_DISABLED_TOPIC = "org/eclipse/kura/net/modem/gps/DISABLED"; public ModemGpsDisabledEvent(Map properties) { super(MODEM_EVENT_GPS_DISABLED_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemGpsEnabledEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ModemGpsEnabledEvent extends Event { /** Topic of the ModemGpsEnabledEvent */ public static final String MODEM_EVENT_GPS_ENABLED_TOPIC = "org/eclipse/kura/net/modem/gps/ENABLED"; /** * @since 2.2 */ public static final String PORT = "port"; /** * @since 2.2 */ public static final String BAUD_RATE = "baudRate"; /** * @since 2.2 */ public static final String DATA_BITS = "bitsPerWord"; /** * @since 2.2 */ public static final String STOP_BITS = "stopBits"; /** * @since 2.2 */ public static final String PARITY = "parity"; /** * @deprecated Use PORT instead */ @SuppressWarnings("checkstyle:constantName") @Deprecated public static final String Port = PORT; /** * @deprecated Use BAUD_RATE instead */ @SuppressWarnings("checkstyle:constantName") @Deprecated public static final String BaudRate = BAUD_RATE; /** * @deprecated Use DATA_BITS instead */ @SuppressWarnings("checkstyle:constantName") @Deprecated public static final String DataBits = DATA_BITS; /** * @deprecated Use STOP_BITS instead */ @SuppressWarnings("checkstyle:constantName") @Deprecated public static final String StopBits = STOP_BITS; /** * @deprecated Use PARITY instead */ @SuppressWarnings("checkstyle:constantName") @Deprecated public static final String Parity = PARITY; public ModemGpsEnabledEvent(Map properties) { super(MODEM_EVENT_GPS_ENABLED_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.List; import org.eclipse.kura.net.NetInterface; import org.osgi.annotation.versioning.ProviderType; /** * Network interface for modems. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ModemInterface extends NetInterface { /** * Reports ppp interface number for this modem * * @return ppp interface number as {@link int} */ public int getPppNum(); /** * Reports identifier string for this modem * * @return modem identifier as {@link String} */ public String getModemIdentifier(); /** * Reports modem's model * * @return model, null if not known */ public String getModel(); /** * Returns modem's manufacturer identification * * @return manufacturer, null if not known */ public String getManufacturer(); /** * Answers modem's serial number * * @return ESN, null if not known */ public String getSerialNumber(); /** * Reports modem's revision identification * * @return array of revision ID's, null if not known */ public String[] getRevisionId(); /** * Reports network technology (e.g. EVDO, HSDPA, etc) * * @return - network technology as ModemTechnologyType */ public List getTechnologyTypes(); /** * Reports if modem is powered on * * @return * true - modem is on
* false - modem is off */ public boolean isPoweredOn(); /** * Reports modem's power mode. (e.g. ONLINE, OFFLINE, LOW_POWER) * * @return modem power mode */ public ModemPowerMode getPowerMode(); /** * Return's the associated ModemDevice for this modem * * @return ModemDevice */ public ModemDevice getModemDevice(); /** * Reports if GPS is supported * * @return * @return * true - GPS is supported
* false - GPS is not supported */ public boolean isGpsSupported(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterfaceAddress.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import org.eclipse.kura.net.NetInterfaceAddress; import org.osgi.annotation.versioning.ProviderType; /** * Modem Interface Address represents the modem state * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ModemInterfaceAddress extends NetInterfaceAddress { /** * Reports signal strength in dBm * * @return signal strength */ public int getSignalStrength(); /** * Reports roaming status * * @return * true - modem is roaming * false - modem is not roaming */ public boolean isRoaming(); /** * Reports connection status * * @return connection status */ public ModemConnectionStatus getConnectionStatus(); /** * Reports number of bytes transmitted during a call * * @return number of bytes transmitted */ public long getBytesTransmitted(); /** * Reports number of bytes received during a call * * @return number of bytes received */ public long getBytesReceived(); /** * Reports Connection Type * * @return connection type */ public ModemConnectionType getConnectionType(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemInterfaceAddressConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.List; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetInterfaceAddressConfig; import org.osgi.annotation.versioning.ProviderType; /** * Modem Interface Address Config represents the modem status and the modem configuration * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface ModemInterfaceAddressConfig extends ModemInterfaceAddress, NetInterfaceAddressConfig { /** * Returns a List of NetConfig Objects associated with a given ModemInterfaceAddressConfig * for a given ModemInterface * * @return the NetConfig Objects associated with the ModemInterfaceAddressConfig */ @Override public List getConfigs(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemManagerService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Collection; import java.util.Optional; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface ModemManagerService { /** * Returns the modem tracked with the given id. * * @deprecated since 2.2 use * {@link ModemManagerService#withModemService(String, Function)} * instead * @param id * The id of the modem, in case of an USB modem, the id is the USB * port as returned by * {@link org.eclipse.kura.usb.UsbModemDevice#getUsbPort()}, in case * of a serial modem the id is the * product name as returned by * {@link org.eclipse.kura.usb.UsbModemDevice#getProductName()} * @return The cellular modem instance, or {@code null} if a modem with the * given id is not currently tracked */ @Deprecated public CellularModem getModemService(String id); /** * Returns the list of currently tracked modems * * @deprecated since 2.2 use * {@link ModemManagerService#withAllModemServices(Function)} * instead * @return the list of currently tracked modems */ @Deprecated public Collection getAllModemServices(); /** * Applies the provided function to the modem named {@code id}. * The function will have exclusive access to the modem until it returns. * * @since 2.2 * * @param * The return type of the function * @param id * The id of the modem, in case of an USB modem, the id is the USB * port as returned by * {@link org.eclipse.kura.usb.UsbModemDevice#getUsbPort()}, in case * of a serial modem the id is the * product name as returned by * {@link org.eclipse.kura.usb.UsbModemDevice#getProductName()} * @param func * @return The result of the provided function applied to the modem */ public T withModemService(String id, ModemFunction, T> func) throws KuraException; /** * Applies the provided function to all currently tracked modems. * The function will have exclusive access to the modems until it returns. * * * @since 2.2 * * @param * The return type of the function * @param func * The function to be called * @return The result of the provided function applied to the modem */ public T withAllModemServices(ModemFunction, T> func) throws KuraException; /** * * @since 2.2 * * @param * @param */ @ConsumerType public interface ModemFunction { public U apply(final T arg) throws KuraException; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemMonitorListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import org.osgi.annotation.versioning.ConsumerType; /** * @deprecated since 3.0 */ @ConsumerType @Deprecated public interface ModemMonitorListener { /** * @since 2.0 */ public void setCellularSignalLevel(String interfaceName, int signalLevel); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemMonitorService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for the ModemMonitor * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface ModemMonitorService { public void registerListener(ModemMonitorListener listener); public void unregisterListener(ModemMonitorListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPdpContext.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.net.modem; /** * @since 1.4 * @deprecated since 3.0 */ @Deprecated public class ModemPdpContext { private final int number; private final ModemPdpContextType type; private final String apn; public ModemPdpContext(int number, ModemPdpContextType type, String apn) { this.number = number; this.type = type; this.apn = apn; } @Override public String toString() { StringBuilder sb = new StringBuilder(this.getClass().getName()); sb.append(super.toString()); sb.append("; ").append("Context Number: ").append(this.number); sb.append("; ").append("PDP Type: ").append(this.type); sb.append("; ").append("APN: ").append(this.apn); return sb.toString(); } public int getNumber() { return this.number; } public ModemPdpContextType getType() { return this.type; } public String getApn() { return this.apn; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPdpContextType.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.net.modem; /** * @since 1.4 * @deprecated since 3.0 */ @Deprecated public enum ModemPdpContextType { IP("IP"), PPP("PPP"), IPV6("IPV6"), IPV4IPV6("IPV4IPV6"); private String contextType; private ModemPdpContextType(String contextType) { this.contextType = contextType; } public String getValue() { return this.contextType; } public static ModemPdpContextType getContextType(String str) { if ("IP".equals(str)) { return IP; } else if ("PPP".equals(str)) { return PPP; } else if ("IPV6".equals(str)) { return IPV6; } else { return IPV4IPV6; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemPowerMode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; public enum ModemPowerMode { /** UNKNOWN Mode **/ UNKNOWN, /** OFFLINE Mode **/ OFFLINE, /** ONLINE Mode **/ ONLINE, /** LOW_POWER Mode **/ LOW_POWER } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemReadyEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * @noextend This class is not intended to be subclassed by clients. * * @deprecated since 3.0 */ @ProviderType @Deprecated public class ModemReadyEvent extends Event { /** Topic of the ModemRemovedEvent */ public static final String MODEM_EVENT_READY_TOPIC = "org/eclipse/kura/net/modem/READY"; public static final String IMEI = "IMEI"; public static final String IMSI = "IMSI"; public static final String ICCID = "ICCID"; public static final String RSSI = "RSSI"; /** * @since 2.2 */ public static final String FW_VERSION = "FW_VER"; /** * @since 2.2 */ public static final String MODEM_DEVICE = "MODEM_DEVICE"; public ModemReadyEvent(Map properties) { super(MODEM_EVENT_READY_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemRegistrationStatus.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; public enum ModemRegistrationStatus { UNKNOWN, NOT_REGISTERED, REGISTERED_HOME, REGISTERED_ROAMING, REGISTRATION_DENIED } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemRemovedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Emitted when a modem is removed from the gateway * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class ModemRemovedEvent extends Event { /** Topic of the ModemRemovedEvent */ public static final String MODEM_EVENT_REMOVED_TOPIC = "org/eclipse/kura/net/modem/REMOVED"; public ModemRemovedEvent(Map properties) { super(MODEM_EVENT_REMOVED_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/ModemTechnologyType.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; public enum ModemTechnologyType { NONE, CDMA, EVDO, LTE, HSPA, HSDPA, UMTS, GSM_GPRS, GPS } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/SerialModemDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.modem; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. * * @deprecated This class is deprecated and should not be used. * @since 2.3 */ @ProviderType @Deprecated public class SerialModemDevice implements ModemDevice { private final String productName; private final String manufacturerName; private final List serialPorts; public SerialModemDevice(String product, String manufacturer, List serialPorts) { this.productName = product; this.manufacturerName = manufacturer; this.serialPorts = serialPorts; } @Override public String getProductName() { return this.productName; } @Override public String getManufacturerName() { return this.manufacturerName; } @Override public List getSerialPorts() { return this.serialPorts; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.manufacturerName == null ? 0 : this.manufacturerName.hashCode()); result = prime * result + (this.productName == null ? 0 : this.productName.hashCode()); result = prime * result + (this.serialPorts == null ? 0 : this.serialPorts.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } SerialModemDevice other = (SerialModemDevice) obj; if (this.manufacturerName == null) { if (other.manufacturerName != null) { return false; } } else if (!this.manufacturerName.equals(other.manufacturerName)) { return false; } if (this.productName == null) { if (other.productName != null) { return false; } } else if (!this.productName.equals(other.productName)) { return false; } if (this.serialPorts == null) { if (other.serialPorts != null) { return false; } } else if (!this.serialPorts.equals(other.serialPorts)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/modem/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides interfaces for instances and configurations of modems. * */ package org.eclipse.kura.net.modem; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains interfaces and event model to manage and configure network interfaces on a given system. *

* * */ package org.eclipse.kura.net; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Route configuration interface * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface RouteConfig extends NetConfig { /** * Gets the description of the route * * @return The description of the route */ public String getDescription(); /** * Gets the destination of the route * * @return The destination of the route */ public IPAddress getDestination(); /** * Gets the gateway of the route * * @return The gateway of the route */ public IPAddress getGateway(); /** * Gets the network mask of the route * * @return The network mask of the route */ public IPAddress getNetmask(); /** * Gets the interface name associated with the route * * @return The interface name associated with the route */ public String getInterfaceName(); /** * Gets the metric of the route * * @return The metric of the route */ public int getMetric(); /** * Compares one route to another * * @return Whether or not the two routes are equal */ public boolean equals(RouteConfig r); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv4 route configs * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface RouteConfig4 extends RouteConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfig6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for IPv6 route configs * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface RouteConfig6 extends RouteConfig { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * Base class for Route configurations * * @param * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class RouteConfigIP implements RouteConfig { private T destination; private T gateway; private T netmask; private String interfaceName; private int metric; public RouteConfigIP(T destination, T gateway, T netmask, String interfaceName, int metric) { super(); this.destination = destination; this.gateway = gateway; this.netmask = netmask; this.interfaceName = interfaceName; this.metric = metric; } @Override public String getDescription() { StringBuffer desc = new StringBuffer(); String gw; if (this.gateway == null) { gw = "default"; } else { gw = this.gateway.getHostAddress(); } desc.append("Destination: " + this.destination.getHostAddress() + ", " + "Gateway: " + gw + ", " + "Netmask: " + this.netmask.getHostAddress() + ", " + "Interface: " + this.interfaceName + ", " + "Metric: " + this.metric); return desc.toString(); } @Override public T getDestination() { return this.destination; } public void setDestination(T destination) { this.destination = destination; } @Override public T getGateway() { return this.gateway; } public void setGateway(T gateway) { this.gateway = gateway; } @Override public T getNetmask() { return this.netmask; } public void setNetmask(T netmask) { this.netmask = netmask; } @Override public String getInterfaceName() { return this.interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } @Override public int getMetric() { return this.metric; } public void setMetric(int metric) { this.metric = metric; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.destination == null ? 0 : this.destination.hashCode()); result = prime * result + (this.gateway == null ? 0 : this.gateway.hashCode()); result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode()); result = prime * result + this.metric; result = prime * result + (this.netmask == null ? 0 : this.netmask.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } @SuppressWarnings("rawtypes") RouteConfigIP other = (RouteConfigIP) obj; if (this.destination == null) { if (other.destination != null) { return false; } } else if (!this.destination.equals(other.destination)) { return false; } if (this.gateway == null) { if (other.gateway != null) { return false; } } else if (!this.gateway.equals(other.gateway)) { return false; } if (this.interfaceName == null) { if (other.interfaceName != null) { return false; } } else if (!this.interfaceName.equals(other.interfaceName)) { return false; } if (this.metric != other.metric) { return false; } if (this.netmask == null) { if (other.netmask != null) { return false; } } else if (!this.netmask.equals(other.netmask)) { return false; } return true; } @Override public boolean isValid() { if (this.destination == null || this.gateway == null || this.netmask == null || this.interfaceName == null) { return false; } return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("RouteConfigIP [m_destination="); builder.append(this.destination); builder.append(", m_gateway="); builder.append(this.gateway); builder.append(", m_netmask="); builder.append(this.netmask); builder.append(", m_interfaceName="); builder.append(this.interfaceName); builder.append(", m_metric="); builder.append(this.metric); builder.append("]"); return builder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP4.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * Implementation of IPv4 route configurations * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class RouteConfigIP4 extends RouteConfigIP implements RouteConfig4 { public RouteConfigIP4(IP4Address destination, IP4Address gateway, IP4Address netmask, String interfaceName, int metric) { super(destination, gateway, netmask, interfaceName, metric); } @Override public boolean equals(RouteConfig route) { if (!compareHostAddress(getDestination(), route.getDestination())) { return false; } else if (!compareHostAddress(getGateway(), route.getGateway())) { return false; } else if (!compareHostAddress(getNetmask(), route.getNetmask())) { return false; } else if (!getInterfaceName().equals(route.getInterfaceName())) { return false; } else if (getMetric() != route.getMetric()) { return false; } return true; } private boolean compareHostAddress(IPAddress adr1, IPAddress adr2) { String host1 = adr1 == null || adr1.getHostAddress() == null ? "" : adr1.getHostAddress(); String host2 = adr2 == null || adr2.getHostAddress() == null ? "" : adr2.getHostAddress(); return host1.equals(host2); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("destination: ").append(getDestination() != null ? getDestination().getHostAddress() : "null") .append(", gateway: ").append(getGateway() != null ? getGateway().getHostAddress() : "null") .append(", netmask: ").append(getNetmask() != null ? getNetmask().getHostAddress() : "null") .append(", interfaceName: ").append(getInterfaceName()).append(", metric: ").append(getMetric()); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RouteConfigIP6.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import org.eclipse.kura.net.IP6Address; import org.osgi.annotation.versioning.ProviderType; /** * Implementation of IPv6 route configurations * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class RouteConfigIP6 extends RouteConfigIP implements RouteConfig6 { public RouteConfigIP6(IP6Address destination, IP6Address gateway, IP6Address netmask, String interfaceName, int metric) { super(destination, gateway, netmask, interfaceName, metric); } @Override public boolean equals(RouteConfig r) { // TODO Auto-generated method stub return false; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/RoutingAgentService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.route; import java.util.Map; import org.eclipse.kura.KuraException; import org.eclipse.kura.net.NetInterfaceConfig; import org.osgi.annotation.versioning.ProviderType; /** * Routing agent service is used to control the static routing table. The * service is used to specify * which interfaces should be used in considering routes and what their * priorities should be. * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface RoutingAgentService { /** * Sets interface priorities * * @param priorities * - list of interface priorities as {@link Map} */ public void setPriorities(Map priorities); /** * Adds interface to RoutingAgent * * @param netIfaceConfig * - interface configuration as {@link NetInterfaceConfig} * @throws KuraException */ @SuppressWarnings("rawtypes") public void addInterface(NetInterfaceConfig netIfaceConfig) throws KuraException; /** * Removes interface from RoutingAgent * * @param interfaceName * - interface name as {@link String} * @throws KuraException */ void removeInterface(String interfaceName) throws KuraException; /** * Get the default gateway * * @return interfaceName - interface name as {@link String} * @throws KuraException */ public String getDefaultGateway() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/route/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides services to manage interfaces and their priorities in the static routing table. * */ package org.eclipse.kura.net.route; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceIpAddress.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status; import java.util.Objects; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * This class describes an IP address with its prefix. * It can be used for IPv4 or IPv6 addresses. * */ @ProviderType public class NetworkInterfaceIpAddress { private final T address; private final short prefix; public NetworkInterfaceIpAddress(T address, short prefix) { this.address = address; this.prefix = prefix; } public T getAddress() { return this.address; } public short getPrefix() { return this.prefix; } @Override public int hashCode() { return Objects.hash(this.address, this.prefix); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } NetworkInterfaceIpAddress other = (NetworkInterfaceIpAddress) obj; return Objects.equals(this.address, other.address) && this.prefix == other.prefix; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceIpAddressStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.net.IPAddress; import org.osgi.annotation.versioning.ProviderType; /** * This class describes the IP address status of a network interface: * a list of IP addresses, an optional gateway and a list of DNS servers * address. It can be used for IPv4 or IPv6 addresses. * */ @ProviderType public class NetworkInterfaceIpAddressStatus { private final List> addresses; private final Optional gateway; private final List dnsServerAddresses; private NetworkInterfaceIpAddressStatus(Builder builder) { this.addresses = builder.addresses; this.gateway = builder.gateway; this.dnsServerAddresses = builder.dnsServerAddresses; } public List> getAddresses() { return this.addresses; } public Optional getGateway() { return this.gateway; } public List getDnsServerAddresses() { return this.dnsServerAddresses; } @Override public int hashCode() { return Objects.hash(this.addresses, this.dnsServerAddresses, this.gateway); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } NetworkInterfaceIpAddressStatus other = (NetworkInterfaceIpAddressStatus) obj; return Objects.equals(this.addresses, other.addresses) && Objects.equals(this.dnsServerAddresses, other.dnsServerAddresses) && Objects.equals(this.gateway, other.gateway); } public static Builder builder() { return new Builder<>(); } public static final class Builder { private List> addresses = Collections.emptyList(); private Optional gateway = Optional.empty(); private List dnsServerAddresses = Collections.emptyList(); private Builder() { } public Builder withAddresses(List> addresses) { this.addresses = addresses; return this; } public Builder withGateway(Optional gateway) { this.gateway = gateway; return this; } public Builder withDnsServerAddresses(List dnsServerAddresses) { this.dnsServerAddresses = dnsServerAddresses; return this; } public NetworkInterfaceIpAddressStatus build() { return new NetworkInterfaceIpAddressStatus<>(this); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceState.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status; /** * The state of a network interface. */ public enum NetworkInterfaceState { /** The device is in an unknown state. */ UNKNOWN, /** The device is recognized but not managed. */ UNMANAGED, /** The device cannot be used (carrier off, rfkill, etc). */ UNAVAILABLE, /** The device is not connected. */ DISCONNECTED, /** The device is preparing to connect. */ PREPARE, /** The device is being configured. */ CONFIG, /** The device is awaiting secrets necessary to continue connection. */ NEED_AUTH, /** The IP settings of the device are being requested and configured. */ IP_CONFIG, /** The device's IP connectivity ability is being determined. */ IP_CHECK, /** The device is waiting for secondary connections to be activated. */ SECONDARIES, /** The device is active. */ ACTIVATED, /** The device's network connection is being turn down. */ DEACTIVATING, /** The device is in a failure state following an attempt to activate it. */ FAILED; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status; import java.util.Arrays; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.IP6Address; import org.osgi.annotation.versioning.ProviderType; /** * Abstract class that contains common properties to describe the status of a * network interface. Specific interfaces, like ethernet or wifi, must extend * this class. * * A network interface is identified by Eclipse Kura using the interfaceId * field. It is used to internally manage the interface. * The interfaceName, instead, is the IP interface as it may appear on the * system. For Ethernet and WiFi interfaces the two values coincide * (i.e. eth0, wlp1s0, ...). * For modems, instead, the id is typically the usb or pci path, while the * interfaceName is the IP interface created when they are connected. * When the modem is disconnected the interfaceName can have a different value. * */ @ProviderType public abstract class NetworkInterfaceStatus { private final String interfaceId; private final String interfaceName; private final byte[] hardwareAddress; private final NetworkInterfaceType type; private final String driver; private final String driverVersion; private final String firmwareVersion; private final boolean virtual; private final NetworkInterfaceState state; private final boolean autoConnect; private final int mtu; private final Optional> interfaceIp4Addresses; private final Optional> interfaceIp6Addresses; protected NetworkInterfaceStatus(NetworkInterfaceStatusBuilder builder) { this.interfaceId = builder.interfaceId; this.interfaceName = builder.interfaceName; this.hardwareAddress = builder.hardwareAddress; this.type = builder.type; this.driver = builder.driver; this.driverVersion = builder.driverVersion; this.firmwareVersion = builder.firmwareVersion; this.virtual = builder.virtual; this.state = builder.state; this.autoConnect = builder.autoConnect; this.mtu = builder.mtu; this.interfaceIp4Addresses = builder.interfaceIp4Addresses; this.interfaceIp6Addresses = builder.interfaceIp6Addresses; } public String getInterfaceId() { return this.interfaceId; } public String getInterfaceName() { return this.interfaceName; } public byte[] getHardwareAddress() { return this.hardwareAddress; } public NetworkInterfaceType getType() { return this.type; } public String getDriver() { return this.driver; } public String getDriverVersion() { return this.driverVersion; } public String getFirmwareVersion() { return this.firmwareVersion; } public boolean isVirtual() { return this.virtual; } public NetworkInterfaceState getState() { return this.state; } public boolean isAutoConnect() { return this.autoConnect; } public int getMtu() { return this.mtu; } public Optional> getInterfaceIp4Addresses() { return this.interfaceIp4Addresses; } public Optional> getInterfaceIp6Addresses() { return this.interfaceIp6Addresses; } /** * Abstract builder for a {@link NetworkInterfaceStatus} object. The builders * for specific interfaces, like ethernet or wifi, must extend this class. * */ public abstract static class NetworkInterfaceStatusBuilder> { private static final String NA = "N/A"; private String interfaceId = NA; private String interfaceName = NA; private byte[] hardwareAddress = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; private NetworkInterfaceType type = NetworkInterfaceType.UNKNOWN; private String driver = NA; private String driverVersion = NA; private String firmwareVersion = NA; private boolean virtual = false; private NetworkInterfaceState state = NetworkInterfaceState.UNKNOWN; private boolean autoConnect = false; private int mtu = 0; private Optional> interfaceIp4Addresses = Optional.empty(); private Optional> interfaceIp6Addresses = Optional.empty(); public T withInterfaceId(String interfaceId) { this.interfaceId = interfaceId; return getThis(); } public T withInterfaceName(String interfacenName) { this.interfaceName = interfacenName; return getThis(); } public T withHardwareAddress(byte[] hardwareAddress) { this.hardwareAddress = hardwareAddress; return getThis(); } protected T withType(NetworkInterfaceType type) { this.type = type; return getThis(); } public T withDriver(String driver) { this.driver = driver; return getThis(); } public T withDriverVersion(String driverVersion) { this.driverVersion = driverVersion; return getThis(); } public T withFirmwareVersion(String firmwareVersion) { this.firmwareVersion = firmwareVersion; return getThis(); } public T withVirtual(boolean virtual) { this.virtual = virtual; return getThis(); } public T withState(NetworkInterfaceState state) { this.state = state; return getThis(); } public T withAutoConnect(boolean autoConnect) { this.autoConnect = autoConnect; return getThis(); } public T withMtu(int mtu) { this.mtu = mtu; return getThis(); } public T withInterfaceIp4Addresses( Optional> interfaceIp4Addresses) { this.interfaceIp4Addresses = interfaceIp4Addresses; return getThis(); } public T withInterfaceIp6Addresses( Optional> interfaceIp6Addresses) { this.interfaceIp6Addresses = interfaceIp6Addresses; return getThis(); } public abstract T getThis(); public abstract NetworkInterfaceStatus build(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(this.hardwareAddress); result = prime * result + Objects.hash(this.autoConnect, this.driver, this.driverVersion, this.firmwareVersion, this.interfaceName, this.interfaceIp4Addresses, this.interfaceIp6Addresses, this.mtu, this.interfaceId, this.state, this.type, this.virtual); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } NetworkInterfaceStatus other = (NetworkInterfaceStatus) obj; return this.autoConnect == other.autoConnect && Objects.equals(this.driver, other.driver) && Objects.equals(this.driverVersion, other.driverVersion) && Objects.equals(this.firmwareVersion, other.firmwareVersion) && Arrays.equals(this.hardwareAddress, other.hardwareAddress) && Objects.equals(this.interfaceName, other.interfaceName) && Objects.equals(this.interfaceIp4Addresses, other.interfaceIp4Addresses) && Objects.equals(this.interfaceIp6Addresses, other.interfaceIp6Addresses) && this.mtu == other.mtu && Objects.equals(this.interfaceId, other.interfaceId) && this.state == other.state && this.type == other.type && this.virtual == other.virtual; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkInterfaceType.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status; /** * The type of a network interface. * */ public enum NetworkInterfaceType { /** The device type is unknown. */ UNKNOWN, /** The device is a wired Ethernet device. */ ETHERNET, /** The device is an 802.11 WiFi device. */ WIFI, /** Unused */ UNUSED1, /** Unused */ UNUSED2, /** The device is a Bluetooth device. */ BT, /** The device is an OLPC mesh networking device. */ OLPC_MESH, /** The device is an 802.16e Mobile WiMAX device. */ WIMAX, /** * The device is a modem supporting one or more of analog telephone, CDMA/EVDO, * GSM/UMTS/HSPA, or LTE standards to access a cellular or wireline data * network. */ MODEM, /** The device is an IP-capable InfiniBand interface. */ INFINIBAND, /** The device is a bond master interface. */ BOND, /** The device is a VLAN interface. */ VLAN, /** The device is an ADSL device. */ ADSL, /** The device is a bridge master interface. */ BRIDGE, /** This is a generic support for unrecognized device types. */ GENERIC, /** The device is a team master interface. */ TEAM, /** The device is a TUN or TAP interface. */ TUN, /** The device is an IP tunnel interface. */ TUNNEL, /** The device is a MACVLAN interface. */ MACVLAN, /** The device is a VXLAN interface. */ VXLAN, /** The device is a VETH interface. */ VETH, /** The device is a MACsec interface. */ MACSEC, /** The device is a dummy interface. */ DUMMY, /** The device is a PPP interface. */ PPP, /** The device is a Open vSwitch interface. */ OVS_INTERFACE, /** The device is a Open vSwitch port. */ OVS_PORT, /** The device is a Open vSwitch bridge. */ OVS_BRIDGE, /** The device is a IEEE 802.15.4 (WPAN) MAC Layer Device. */ WPAN, /** The device is a 6LoWPAN interface. */ SIXLOWPAN, /** The device is a WireGuard interface. */ WIREGUARD, /** The device is an 802.11 Wi-Fi P2P device. */ WIFI_P2P, /** The device is a VRF (Virtual Routing and Forwarding) interface. */ VRF, /** The device is a loopback device. */ LOOPBACK; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/NetworkStatusService.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * ******************************************************************************/ package org.eclipse.kura.net.status; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Service API for getting the network interfaces status. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface NetworkStatusService { /** * Return an optional {@link NetworkInterfaceStatus} of the given network * interface selected by its id. For Ethernet and WiFi interfaces, the * identifier is typically the interface name. For the modems, instead, * it is the usb or pci path. * If the interface doesn't exist, an Empty value is returned. * * @param interfaceId * the identifier of the network interface * @return the {@link NetworkInterfaceStatus} * @throws KuraException * when an error occurs while retrieving the status of the * given interface */ public Optional getNetworkStatus(String interfaceId) throws KuraException; /** * Return an optional {@link NetworkInterfaceStatus} of the given network * interface selected by its id.For Ethernet and WiFi interfaces, the * identifier is typically the interface name. For the modems, instead, * it is the usb or pci path. * If the interface doesn't exist, an Empty value is returned. * * @param interfaceId * the identifier of the network interface * @param recompute * If set to true, the NetworkStatusService will perform some additional expensive operations (like AP * scanning) to ensure the status returned by the method is up to date. If set to false, it will return * the status as returned by the network configuration provider. * @return the {@link NetworkInterfaceStatus} * @throws KuraException * when an error occurs while retrieving the status of the * given interface */ public Optional getNetworkStatus(String interfaceId, boolean recompute) throws KuraException; /** * Return the identifiers of the network interfaces detected in the * system. For Ethernet and WiFi interfaces, the identifier is typically * the interface name. For the modems, instead, it is the usb or pci path. * * @return a list containing the network interface identifiers */ public List getInterfaceIds() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/ethernet/EthernetInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.ethernet; import java.util.Objects; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.osgi.annotation.versioning.ProviderType; /** * Class that contains specific properties to describe the status of an * Ethernet interface. * */ @ProviderType public class EthernetInterfaceStatus extends NetworkInterfaceStatus { private final boolean linkUp; private EthernetInterfaceStatus(EthernetInterfaceStatusBuilder builder) { super(builder); this.linkUp = builder.linkUp; } public boolean isLinkUp() { return this.linkUp; } public static EthernetInterfaceStatusBuilder builder() { return new EthernetInterfaceStatusBuilder(); } public static class EthernetInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder { private boolean linkUp = false; public EthernetInterfaceStatusBuilder withIsLinkUp(boolean linkUp) { this.linkUp = linkUp; return getThis(); } @Override public EthernetInterfaceStatus build() { withType(NetworkInterfaceType.ETHERNET); return new EthernetInterfaceStatus(this); } @Override public EthernetInterfaceStatusBuilder getThis() { return this; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Objects.hash(this.linkUp); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj) || getClass() != obj.getClass()) { return false; } EthernetInterfaceStatus other = (EthernetInterfaceStatus) obj; return this.linkUp == other.linkUp; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/ethernet/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides classes for describing the status of an Ethernet interface. * */ package org.eclipse.kura.net.status.ethernet; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/loopback/LoopbackInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.loopback; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.osgi.annotation.versioning.ProviderType; /** * Class that contains specific properties to describe the status of a * Loopback interface. * */ @ProviderType public class LoopbackInterfaceStatus extends NetworkInterfaceStatus { private LoopbackInterfaceStatus(LoopbackInterfaceStatusBuilder builder) { super(builder); } public static LoopbackInterfaceStatusBuilder builder() { return new LoopbackInterfaceStatusBuilder(); } public static class LoopbackInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder { @Override public LoopbackInterfaceStatus build() { withType(NetworkInterfaceType.LOOPBACK); return new LoopbackInterfaceStatus(this); } @Override public LoopbackInterfaceStatusBuilder getThis() { return this; } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/loopback/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides classes for describing the status of a Loopback interface. * */ package org.eclipse.kura.net.status.loopback; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/AccessTechnology.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The specific technology types used when a modem is connected or registered to * a network. * */ public enum AccessTechnology { UNKNOWN, POTS, GSM, GSM_COMPACT, GPRS, EDGE, UMTS, HSDPA, HSUPA, HSPA, HSPA_PLUS, ONEXRTT, EVDO0, EVDOA, EVDOB, LTE, FIVEGNR, LTE_CAT_M, LTE_NB_IOT, ANY; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/Bearer.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; import java.util.Objects; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; /** * This class describes the Bearer or Context associated to a modem connection. * */ @ProviderType public class Bearer { private final String name; private final boolean connected; private final String apn; private final Set ipTypes; private final long bytesTransmitted; private final long bytesReceived; public Bearer(String name, boolean connected, String apn, Set ipTypes, long bytesTransmitted, long bytesReceived) { super(); this.name = name; this.connected = connected; this.apn = apn; this.ipTypes = ipTypes; this.bytesTransmitted = bytesTransmitted; this.bytesReceived = bytesReceived; } public String getName() { return this.name; } public boolean isConnected() { return this.connected; } public String getApn() { return this.apn; } public Set getIpTypes() { return this.ipTypes; } public long getBytesTransmitted() { return this.bytesTransmitted; } public long getBytesReceived() { return this.bytesReceived; } @Override public int hashCode() { return Objects.hash(this.apn, this.bytesReceived, this.bytesTransmitted, this.connected, this.ipTypes, this.name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } Bearer other = (Bearer) obj; return Objects.equals(this.apn, other.apn) && this.bytesReceived == other.bytesReceived && this.bytesTransmitted == other.bytesTransmitted && this.connected == other.connected && Objects.equals(this.ipTypes, other.ipTypes) && Objects.equals(this.name, other.name); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/BearerIpType.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The type of Bearer or Context associated to a modem connection. * */ public enum BearerIpType { NONE, IPV4, IPV6, IPV4V6, NON_IP, ANY; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ESimStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The status of an ESIM. * */ public enum ESimStatus { UNKNOWN, NO_PROFILES, WITH_PROFILES; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemBand.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The radio bands supported by a modem when connected to a mobile network. * */ public enum ModemBand { UNKNOWN, EGSM, DCS, PCS, G850, UTRAN_1, UTRAN_3, UTRAN_4, UTRAN_6, UTRAN_5, UTRAN_8, UTRAN_9, UTRAN_2, UTRAN_7, G450, G480, G750, G380, G410, G710, G810, EUTRAN_1, EUTRAN_2, EUTRAN_3, EUTRAN_4, EUTRAN_5, EUTRAN_6, EUTRAN_7, EUTRAN_8, EUTRAN_9, EUTRAN_10, EUTRAN_11, EUTRAN_12, EUTRAN_13, EUTRAN_14, EUTRAN_17, EUTRAN_18, EUTRAN_19, EUTRAN_20, EUTRAN_21, EUTRAN_22, EUTRAN_23, EUTRAN_24, EUTRAN_25, EUTRAN_26, EUTRAN_27, EUTRAN_28, EUTRAN_29, EUTRAN_30, EUTRAN_31, EUTRAN_32, EUTRAN_33, EUTRAN_34, EUTRAN_35, EUTRAN_36, EUTRAN_37, EUTRAN_38, EUTRAN_39, EUTRAN_40, EUTRAN_41, EUTRAN_42, EUTRAN_43, EUTRAN_44, EUTRAN_45, EUTRAN_46, EUTRAN_47, EUTRAN_48, EUTRAN_49, EUTRAN_50, EUTRAN_51, EUTRAN_52, EUTRAN_53, EUTRAN_54, EUTRAN_55, EUTRAN_56, EUTRAN_57, EUTRAN_58, EUTRAN_59, EUTRAN_60, EUTRAN_61, EUTRAN_62, EUTRAN_63, EUTRAN_64, EUTRAN_65, EUTRAN_66, EUTRAN_67, EUTRAN_68, EUTRAN_69, EUTRAN_70, EUTRAN_71, EUTRAN_85, CDMA_BC0, CDMA_BC1, CDMA_BC2, CDMA_BC3, CDMA_BC4, CDMA_BC5, CDMA_BC6, CDMA_BC7, CDMA_BC8, CDMA_BC9, CDMA_BC10, CDMA_BC11, CDMA_BC12, CDMA_BC13, CDMA_BC14, CDMA_BC15, CDMA_BC16, CDMA_BC17, CDMA_BC18, CDMA_BC19, UTRAN_10, UTRAN_11, UTRAN_12, UTRAN_13, UTRAN_14, UTRAN_19, UTRAN_20, UTRAN_21, UTRAN_22, UTRAN_25, UTRAN_26, UTRAN_32, ANY, NGRAN_1, NGRAN_2, NGRAN_3, NGRAN_5, NGRAN_7, NGRAN_8, NGRAN_12, NGRAN_13, NGRAN_14, NGRAN_18, NGRAN_20, NGRAN_25, NGRAN_26, NGRAN_28, NGRAN_29, NGRAN_30, NGRAN_34, NGRAN_38, NGRAN_39, NGRAN_40, NGRAN_41, NGRAN_48, NGRAN_50, NGRAN_51, NGRAN_53, NGRAN_65, NGRAN_66, NGRAN_70, NGRAN_71, NGRAN_74, NGRAN_75, NGRAN_76, NGRAN_77, NGRAN_78, NGRAN_79, NGRAN_80, NGRAN_81, NGRAN_82, NGRAN_83, NGRAN_84, NGRAN_86, NGRAN_89, NGRAN_90, NGRAN_91, NGRAN_92, NGRAN_93, NGRAN_94, NGRAN_95, NGRAN_257, NGRAN_258, NGRAN_260, NGRAN_261; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemCapability.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The generic access technologies families supported by a modem. * */ public enum ModemCapability { /** The modem has no capabilities. */ NONE, /** * The modem supports the Plain Old Telephone Service (analog wired telephone * network). */ POTS, /** The modem supports EVDO revision 0, A or B. */ EVDO, /** * The modem supports at least one of GSM, GPRS, EDGE, UMTS, HSDPA, HSUPA or * HSPA+ technologies. */ GSM_UMTS, /** The modem has LTE capabilities */ LTE, /** The modem supports Iridium technology. */ IRIDIUM, /** The modem supports 5GNR. */ FIVE_GNR, /** The modem supports TDS. */ TDS, /** The modem supports all capabilities. */ ANY; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemConnectionStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The status of a modem. * */ public enum ModemConnectionStatus { /** The modem is unavailable */ FAILED, /** The modem is in an unknown state. */ UNKNOWN, /** The modem is being initialised. */ INITIALIZING, /** The modem is locked. */ LOCKED, /** The modem is disabled and powered off. */ DISABLED, /** The modem is disabling. */ DISABLING, /** The modem is enabling. */ ENABLING, /** The modem is enabled but not registered to a network provider. */ ENABLED, /** The modem is searching for a network provider. */ SEARCHING, /** The modem is registered to a network provider. */ REGISTERED, /** The modem is disconnecting. */ DISCONNECTING, /** The modem is connecting. */ CONNECTING, /** The modem is connected. */ CONNECTED; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemGpsMode.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /* * The GPS mode supported by the modem. * * @since 2.8 */ public enum ModemGpsMode { /* * Unmanaged GPS mode. In this mode the GPS device of the modem will be setup but not directly managed, therefore * freeing the serial port for other services to use. */ UNMANAGED, /* * Managed GPS mode. In this mode the GPS device of the modem will be setup and directly managed (typically by * ModemManager) therefore the serial port won't be available for other services to use. */ MANAGED_GPS } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import org.eclipse.kura.net.modem.ModemConnectionType; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.osgi.annotation.versioning.ProviderType; /** * Class that contains specific properties to describe the status of a * Modem interface. * */ @ProviderType public class ModemInterfaceStatus extends NetworkInterfaceStatus { private final String model; private final String manufacturer; private final String serialNumber; private final String softwareRevision; private final String hardwareRevision; private final String primaryPort; private final Map ports; private final List> supportedModemCapabilities; private final Set currentModemCapabilities; private final ModemPowerState powerState; private final Set supportedModes; private final ModemModePair currentModes; private final Set supportedBands; private final Set currentBands; private final boolean gpsSupported; private final Set supportedGpsModes; private final List availableSims; private final boolean simLocked; private final List bearers; private final ModemConnectionType connectionType; private final ModemConnectionStatus connectionStatus; private final Set accessTechnologies; private final int signalQuality; private final int signalStrength; private final RegistrationStatus registrationStatus; private final String operatorName; private ModemInterfaceStatus(ModemInterfaceStatusBuilder builder) { super(builder); this.model = builder.model; this.manufacturer = builder.manufacturer; this.serialNumber = builder.serialNumber; this.softwareRevision = builder.softwareRevision; this.hardwareRevision = builder.hardwareRevision; this.primaryPort = builder.primaryPort; this.ports = builder.ports; this.supportedModemCapabilities = builder.supportedModemCapabilities; this.currentModemCapabilities = builder.currentModemCapabilities; this.powerState = builder.powerState; this.supportedModes = builder.supportedModes; this.currentModes = builder.currentModes; this.supportedBands = builder.supportedBands; this.currentBands = builder.currentBands; this.gpsSupported = builder.gpsSupported; this.supportedGpsModes = builder.supportedGpsModes; this.availableSims = builder.availableSims; this.simLocked = builder.simLocked; this.bearers = builder.bearers; this.connectionType = builder.connectionType; this.connectionStatus = builder.connectionStatus; this.accessTechnologies = builder.accessTechnologies; this.signalQuality = builder.signalQuality; this.registrationStatus = builder.registrationStatus; this.operatorName = builder.operatorName; this.signalStrength = builder.signalStrength; } public String getModel() { return this.model; } public String getManufacturer() { return this.manufacturer; } public String getSerialNumber() { return this.serialNumber; } public String getSoftwareRevision() { return this.softwareRevision; } public String getHardwareRevision() { return this.hardwareRevision; } public String getPrimaryPort() { return this.primaryPort; } public Map getPorts() { return this.ports; } /** * @deprecated use {@link ModemInterfaceStatus#getAllSupportedModemCapabilities()} instead. * This method returns only the first ModemCapability if any. * @since 2.8 */ @Deprecated public Set getSupportedModemCapabilities() { if (!this.supportedModemCapabilities.isEmpty()) { return this.supportedModemCapabilities.get(0); } else { return new HashSet(); } } /** * @since 2.8 */ public List> getAllSupportedModemCapabilities() { return this.supportedModemCapabilities; } public Set getCurrentModemCapabilities() { return this.currentModemCapabilities; } public ModemPowerState getPowerState() { return this.powerState; } public Set getSupportedModes() { return this.supportedModes; } public ModemModePair getCurrentModes() { return this.currentModes; } public Set getSupportedBands() { return this.supportedBands; } public Set getCurrentBands() { return this.currentBands; } public Boolean isGpsSupported() { return this.gpsSupported; } /* * @since 2.8 */ public Set getSupporteGpsModes() { return this.supportedGpsModes; } public List getAvailableSims() { return this.availableSims; } public boolean isSimLocked() { return this.simLocked; } public List getBearers() { return this.bearers; } public ModemConnectionType getConnectionType() { return this.connectionType; } public ModemConnectionStatus getConnectionStatus() { return this.connectionStatus; } public Set getAccessTechnologies() { return this.accessTechnologies; } public int getSignalQuality() { return this.signalQuality; } public RegistrationStatus getRegistrationStatus() { return this.registrationStatus; } public String getOperatorName() { return this.operatorName; } public int getSignalStrength() { return this.signalStrength; } public static ModemInterfaceStatusBuilder builder() { return new ModemInterfaceStatusBuilder(); } public static class ModemInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder { private static final String NA = "N/A"; private String model = NA; private String manufacturer = NA; private String serialNumber = NA; private String softwareRevision = NA; private String hardwareRevision = NA; private String primaryPort = NA; private Map ports = Collections.emptyMap(); private List> supportedModemCapabilities = new ArrayList<>(); private Set currentModemCapabilities = EnumSet.of(ModemCapability.NONE); private ModemPowerState powerState = ModemPowerState.UNKNOWN; private Set supportedModes = Collections.emptySet(); private ModemModePair currentModes = new ModemModePair(Collections.emptySet(), ModemMode.NONE); private Set supportedBands = EnumSet.of(ModemBand.UNKNOWN); private Set currentBands = EnumSet.of(ModemBand.UNKNOWN); private boolean gpsSupported = false; private Set supportedGpsModes = Collections.emptySet(); private List availableSims = Collections.emptyList(); private boolean simLocked = false; private List bearers = Collections.emptyList(); private ModemConnectionType connectionType = ModemConnectionType.DirectIP; private ModemConnectionStatus connectionStatus = ModemConnectionStatus.UNKNOWN; private Set accessTechnologies = EnumSet.of(AccessTechnology.UNKNOWN); private int signalQuality = 0; private int signalStrength = -113; private RegistrationStatus registrationStatus = RegistrationStatus.UNKNOWN; private String operatorName = NA; public ModemInterfaceStatusBuilder withModel(String model) { this.model = model; return getThis(); } public ModemInterfaceStatusBuilder withManufacturer(String manufacturer) { this.manufacturer = manufacturer; return getThis(); } public ModemInterfaceStatusBuilder withSerialNumber(String serialNumber) { this.serialNumber = serialNumber; return getThis(); } public ModemInterfaceStatusBuilder withSoftwareRevision(String softwareRevision) { this.softwareRevision = softwareRevision; return getThis(); } public ModemInterfaceStatusBuilder withHardwareRevision(String hardwareRevision) { this.hardwareRevision = hardwareRevision; return getThis(); } public ModemInterfaceStatusBuilder withPrimaryPort(String primaryPort) { this.primaryPort = primaryPort; return getThis(); } public ModemInterfaceStatusBuilder withPorts(Map ports) { this.ports = ports; return getThis(); } /** * @deprecated To add all the supported capabilities, call this method multiple times with every set of * ModemCapability. * Instead use * {@link ModemInterfaceStatus#withAllSupportedModemCapabilities(List> * supportedModemCapabilities)} to add the ModemCapabilities all at once. * @since 2.8 */ @Deprecated public ModemInterfaceStatusBuilder withSupportedModemCapabilities( Set supportedModemCapabilities) { this.supportedModemCapabilities.add(supportedModemCapabilities); return getThis(); } /** * @since 2.8 */ public ModemInterfaceStatusBuilder withAllSupportedModemCapabilities( List> supportedModemCapabilities) { this.supportedModemCapabilities = supportedModemCapabilities; return getThis(); } public ModemInterfaceStatusBuilder withCurrentModemCapabilities(Set currentModemCapabilities) { this.currentModemCapabilities = currentModemCapabilities; return getThis(); } public ModemInterfaceStatusBuilder withPowerState(ModemPowerState powerState) { this.powerState = powerState; return getThis(); } public ModemInterfaceStatusBuilder withSupportedModes(Set supportedModes) { this.supportedModes = supportedModes; return getThis(); } public ModemInterfaceStatusBuilder withCurrentModes(ModemModePair currentModes) { this.currentModes = currentModes; return getThis(); } public ModemInterfaceStatusBuilder withSupportedBands(Set supportedBands) { this.supportedBands = supportedBands; return getThis(); } public ModemInterfaceStatusBuilder withCurrentBands(Set currentBands) { this.currentBands = currentBands; return getThis(); } public ModemInterfaceStatusBuilder withGpsSupported(Boolean gpsSupported) { this.gpsSupported = gpsSupported; return getThis(); } public ModemInterfaceStatusBuilder withSupportedGpsModes(Set supportedGpsModes) { this.supportedGpsModes = supportedGpsModes; return getThis(); } public ModemInterfaceStatusBuilder withAvailableSims(List availableSims) { this.availableSims = availableSims; return getThis(); } public ModemInterfaceStatusBuilder withSimLocked(boolean simLocked) { this.simLocked = simLocked; return getThis(); } public ModemInterfaceStatusBuilder withBearers(List bearers) { this.bearers = bearers; return getThis(); } public ModemInterfaceStatusBuilder withConnectionType(ModemConnectionType connectionType) { this.connectionType = connectionType; return getThis(); } public ModemInterfaceStatusBuilder withConnectionStatus(ModemConnectionStatus connectionStatus) { this.connectionStatus = connectionStatus; return getThis(); } public ModemInterfaceStatusBuilder withAccessTechnologies(Set accessTechnologies) { this.accessTechnologies = accessTechnologies; return getThis(); } public ModemInterfaceStatusBuilder withSignalQuality(int signalQuality) { this.signalQuality = signalQuality; return getThis(); } public ModemInterfaceStatusBuilder withSignalStrength(int signalStrength) { this.signalStrength = signalStrength; return getThis(); } public ModemInterfaceStatusBuilder withRegistrationStatus(RegistrationStatus registrationStatus) { this.registrationStatus = registrationStatus; return getThis(); } public ModemInterfaceStatusBuilder withOperatorName(String operatorName) { this.operatorName = operatorName; return getThis(); } @Override public ModemInterfaceStatus build() { withType(NetworkInterfaceType.MODEM); return new ModemInterfaceStatus(this); } @Override public ModemInterfaceStatusBuilder getThis() { return this; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Objects.hash(this.accessTechnologies, this.availableSims, this.bearers, this.connectionStatus, this.connectionType, this.currentBands, this.currentModemCapabilities, this.currentModes, this.gpsSupported, this.hardwareRevision, this.manufacturer, this.model, this.operatorName, this.ports, this.powerState, this.primaryPort, this.registrationStatus, this.signalStrength, this.serialNumber, this.signalQuality, this.simLocked, this.softwareRevision, this.supportedBands, this.supportedModemCapabilities, this.supportedModes); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj) || getClass() != obj.getClass()) { return false; } ModemInterfaceStatus other = (ModemInterfaceStatus) obj; return Objects.equals(this.accessTechnologies, other.accessTechnologies) && Objects.equals(this.availableSims, other.availableSims) && Objects.equals(this.bearers, other.bearers) && this.connectionStatus == other.connectionStatus && this.connectionType == other.connectionType && Objects.equals(this.currentBands, other.currentBands) && Objects.equals(this.currentModemCapabilities, other.currentModemCapabilities) && Objects.equals(this.currentModes, other.currentModes) && this.gpsSupported == other.gpsSupported && Objects.equals(this.hardwareRevision, other.hardwareRevision) && Objects.equals(this.manufacturer, other.manufacturer) && Objects.equals(this.model, other.model) && Objects.equals(this.operatorName, other.operatorName) && Objects.equals(this.ports, other.ports) && this.powerState == other.powerState && Objects.equals(this.primaryPort, other.primaryPort) && this.registrationStatus == other.registrationStatus && this.signalStrength == other.signalStrength && Objects.equals(this.serialNumber, other.serialNumber) && this.signalQuality == other.signalQuality && this.simLocked == other.simLocked && Objects.equals(this.softwareRevision, other.softwareRevision) && Objects.equals(this.supportedBands, other.supportedBands) && Objects.equals(this.supportedModemCapabilities, other.supportedModemCapabilities) && Objects.equals(this.supportedModes, other.supportedModes); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemMode.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The generic access mode a modem supports. * */ public enum ModemMode { NONE, CS, MODE_2G, MODE_3G, MODE_4G, MODE_5G, ANY; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemModePair.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; import java.util.Objects; import java.util.Set; /** * This class represents a pair of Modem Mode list and a preferred one. * */ public class ModemModePair { private final Set modes; private final ModemMode preferredMode; public ModemModePair(Set modes, ModemMode preferredMode) { this.modes = modes; this.preferredMode = preferredMode; } public Set getModes() { return this.modes; } public ModemMode getPreferredMode() { return this.preferredMode; } @Override public int hashCode() { return Objects.hash(this.modes, this.preferredMode); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } ModemModePair other = (ModemModePair) obj; return Objects.equals(this.modes, other.modes) && this.preferredMode == other.preferredMode; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemPortType.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The type of a modem port. * */ public enum ModemPortType { UNKNOWN, NET, AT, QCDM, GPS, QMI, MBIM, AUDIO, IGNORED; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/ModemPowerState.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The power state of a modem. * */ public enum ModemPowerState { UNKNOWN, OFF, LOW, ON; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/RegistrationStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The registration status of a modem when connected to a mobile network. * */ public enum RegistrationStatus { IDLE, HOME, SEARCHING, DENIED, UNKNOWN, ROAMING, HOME_SMS_ONLY, ROAMING_SMS_ONLY, EMERGENCY_ONLY, HOME_CSFB_NOT_PREFERRED, ROAMING_CSFB_NOT_PREFERRED, ATTACHED_RLOS; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/Sim.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; import java.util.Objects; import org.osgi.annotation.versioning.ProviderType; /** * This class contains all relevant properties to describe a SIM (Subscriber * Identity Module). * */ @ProviderType public class Sim { private final boolean active; private final boolean primary; private final String iccid; private final String imsi; private final String eid; private final String operatorName; private final String operatorIdentifier; private final SimType simType; private final ESimStatus eSimStatus; public Sim(SimBuilder builder) { this.active = builder.active; this.primary = builder.primary; this.iccid = builder.iccid; this.imsi = builder.imsi; this.eid = builder.eid; this.operatorName = builder.operatorName; this.operatorIdentifier = builder.operatorIdentifier; this.simType = builder.simType; this.eSimStatus = builder.eSimStatus; } public boolean isActive() { return this.active; } public boolean isPrimary() { return this.primary; } public String getIccid() { return this.iccid; } public String getImsi() { return this.imsi; } public String getEid() { return this.eid; } public String getOperatorName() { return this.operatorName; } /** * * @since 2.8 */ public String getOperatorIdentifier() { return this.operatorIdentifier; } public SimType getSimType() { return this.simType; } public ESimStatus geteSimStatus() { return this.eSimStatus; } public static SimBuilder builder() { return new SimBuilder(); } public static final class SimBuilder { private boolean active; private boolean primary; private String iccid = "NA"; private String imsi = "NA"; private String eid = "NA"; private String operatorName = "NA"; private String operatorIdentifier = "NA"; private SimType simType = SimType.UNKNOWN; private ESimStatus eSimStatus = ESimStatus.UNKNOWN; private SimBuilder() { } public SimBuilder withActive(boolean active) { this.active = active; return this; } public SimBuilder withPrimary(boolean primary) { this.primary = primary; return this; } public SimBuilder withIccid(String iccid) { this.iccid = iccid; return this; } public SimBuilder withImsi(String imsi) { this.imsi = imsi; return this; } public SimBuilder withEid(String eid) { this.eid = eid; return this; } public SimBuilder withOperatorName(String operatorName) { this.operatorName = operatorName; return this; } /** * * @since 2.8 */ public SimBuilder withOperatorIdentifier(String operatorIdentifier) { this.operatorIdentifier = operatorIdentifier; return this; } public SimBuilder withSimType(SimType simType) { this.simType = simType; return this; } public SimBuilder withESimStatus(ESimStatus eSimStatus) { this.eSimStatus = eSimStatus; return this; } public Sim build() { return new Sim(this); } } @Override public int hashCode() { return Objects.hash(this.active, this.primary, this.eSimStatus, this.eid, this.iccid, this.imsi, this.operatorName, this.operatorIdentifier, this.simType); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } Sim other = (Sim) obj; return this.active == other.active && this.primary == other.primary && this.eSimStatus == other.eSimStatus && Objects.equals(this.eid, other.eid) && Objects.equals(this.iccid, other.iccid) && Objects.equals(this.imsi, other.imsi) && Objects.equals(this.operatorName, other.operatorName) && Objects.equals(this.operatorIdentifier, other.operatorIdentifier) && this.simType == other.simType; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/SimType.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.modem; /** * The SIM (Subscriber Identity Module) type. * */ public enum SimType { UNKNOWN, PHYSICAL, ESIM; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/modem/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides classes for describing the status of a modem interface. * */ package org.eclipse.kura.net.status.modem; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides interfaces and classes for describing the network status of a * device. * */ package org.eclipse.kura.net.status; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/vlan/VlanInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Areti and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Areti * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.vlan; import java.util.Objects; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.osgi.annotation.versioning.ProviderType; /** * Class that contains specific properties to describe the status of a * Vlan. * */ @ProviderType public class VlanInterfaceStatus extends NetworkInterfaceStatus { private final String parentInterface; private final int vlanId; private VlanInterfaceStatus(VlanInterfaceStatusBuilder builder) { super(builder); this.vlanId = builder.vlanId; this.parentInterface = builder.parentInterface; } public int getVlanId() { return this.vlanId; } public String getParentInterface() { return this.parentInterface; } public static VlanInterfaceStatusBuilder builder() { return new VlanInterfaceStatusBuilder(); } public static class VlanInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder { private String parentInterface; private int vlanId; public VlanInterfaceStatusBuilder withParentInterface(String parentInterface) { this.parentInterface = parentInterface; return getThis(); } public VlanInterfaceStatusBuilder withVlanId(int vlanId) { this.vlanId = vlanId; return getThis(); } public VlanInterfaceStatus build() { withType(NetworkInterfaceType.VLAN); return new VlanInterfaceStatus(this); } public VlanInterfaceStatusBuilder getThis() { return this; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Objects.hash(this.vlanId, this.parentInterface); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj) || getClass() != obj.getClass()) { return false; } VlanInterfaceStatus other = (VlanInterfaceStatus) obj; return this.vlanId == other.vlanId && Objects.equals(this.parentInterface, other.getParentInterface()); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/vlan/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Areti and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Areti * Eurotech ******************************************************************************/ /** * Provides classes for describing the status of a Vlan. * */ package org.eclipse.kura.net.status.vlan; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiAccessPoint.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; /** * This class describes a Wifi Access Point. * It can be used both for describing a detected AP after a WiFi scan when in * Station mode and the provided AP when in Master (or Access Point) mode. * */ @ProviderType public class WifiAccessPoint { private final String ssid; private final byte[] hardwareAddress; private final WifiChannel channel; private final WifiMode mode; private final long maxBitrate; private final int signalQuality; private final int signalStrength; private final Set wpaSecurity; private final Set rsnSecurity; private final Set flags; private WifiAccessPoint(WifiAccessPointBuilder builder) { this.ssid = builder.ssid; this.hardwareAddress = builder.hardwareAddress; this.channel = builder.channel; this.mode = builder.mode; this.maxBitrate = builder.maxBitrate; this.signalQuality = builder.signalQuality; this.signalStrength = builder.signalStrength; this.wpaSecurity = builder.wpaSecurity; this.rsnSecurity = builder.rsnSecurity; this.flags = builder.flags; } /** * Return the Service Set IDentifier of the WiFi network. * * @return a string representing the ssid */ public String getSsid() { return this.ssid; } /** * Return the Basic Service Set IDentifier of the WiFi access point. * * @return a string representing the the bssid */ public byte[] getHardwareAddress() { return this.hardwareAddress; } /** * Return the {@link WifiChannel} used by the WiFi access point. * * @return a {@link WifiChannel} object */ public WifiChannel getChannel() { return this.channel; } /** * Return the {@link WifiMode} of the wireless interface. * * @return a {@link WifiMode} entry */ public WifiMode getMode() { return this.mode; } /** * Return the maximum bitrate this access point is capable of. * * @return a long value representing the bitrate */ public long getMaxBitrate() { return this.maxBitrate; } /** * Return the current signal quality of the access point in percentage. * * @return an integer value between 0 and 100 */ public int getSignalQuality() { return this.signalQuality; } /** * Return the current signal strength of the access point in dBm. * * @return an integer value representing the rssi */ public int getSignalStrength() { return this.signalStrength; } /** * Return the WPA capabilities of the access point. * * @return a set of {@link WifiSecurity} representing the capabilities */ public Set getWpaSecurity() { return this.wpaSecurity; } /** * Return the RSN capabilities of the access point. * * @return a set of {@link WifiSecurity} representing the capabilities */ public Set getRsnSecurity() { return this.rsnSecurity; } /** * Return the capabilities of the access point. * * @return a set of {@link WifiFlag} representing the capabilities * * @since 2.8 */ public Set getFlags() { return this.flags; } public static WifiAccessPointBuilder builder() { return new WifiAccessPointBuilder(); } public static final class WifiAccessPointBuilder { private String ssid; private byte[] hardwareAddress; private WifiChannel channel; private WifiMode mode; private long maxBitrate; private int signalQuality; private int signalStrength; private Set wpaSecurity = Collections.emptySet(); private Set rsnSecurity = Collections.emptySet(); private Set flags = Collections.emptySet(); private WifiAccessPointBuilder() { } public WifiAccessPointBuilder withSsid(String ssid) { this.ssid = ssid; return this; } public WifiAccessPointBuilder withHardwareAddress(byte[] hardwareAddress) { this.hardwareAddress = hardwareAddress; return this; } public WifiAccessPointBuilder withChannel(WifiChannel channel) { this.channel = channel; return this; } public WifiAccessPointBuilder withMode(WifiMode mode) { this.mode = mode; return this; } public WifiAccessPointBuilder withMaxBitrate(long maxBitrate) { this.maxBitrate = maxBitrate; return this; } public WifiAccessPointBuilder withSignalQuality(int signalQuality) { this.signalQuality = signalQuality; return this; } public WifiAccessPointBuilder withSignalStrength(int signalStrength) { this.signalStrength = signalStrength; return this; } public WifiAccessPointBuilder withWpaSecurity(Set wpaSecurity) { this.wpaSecurity = wpaSecurity; return this; } public WifiAccessPointBuilder withRsnSecurity(Set rsnSecurity) { this.rsnSecurity = rsnSecurity; return this; } public WifiAccessPointBuilder withFlags(Set flags) { this.flags = flags; return this; } public WifiAccessPoint build() { return new WifiAccessPoint(this); } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(this.hardwareAddress); result = prime * result + Objects.hash(this.channel, this.maxBitrate, this.mode, this.rsnSecurity, this.signalQuality, this.signalStrength, this.ssid, this.wpaSecurity, this.flags); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } WifiAccessPoint other = (WifiAccessPoint) obj; return Objects.equals(this.channel, other.channel) && Arrays.equals(this.hardwareAddress, other.hardwareAddress) && this.maxBitrate == other.maxBitrate && this.mode == other.mode && Objects.equals(this.rsnSecurity, other.rsnSecurity) && this.signalQuality == other.signalQuality && Objects.equals(this.ssid, other.ssid) && Objects.equals(this.signalStrength, other.signalStrength) && Objects.equals(this.wpaSecurity, other.wpaSecurity) && Objects.equals(this.flags, other.flags); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiCapability.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; /** * The capability of a WiFi interface. * */ public enum WifiCapability { /** The device has no encryption/authentication capabilities */ NONE, /** The device supports 40/64-bit WEP encryption. */ CIPHER_WEP40, /** The device supports 104/128-bit WEP encryption. */ CIPHER_WEP104, /** The device supports the TKIP encryption. */ CIPHER_TKIP, /** The device supports the AES/CCMP encryption. */ CIPHER_CCMP, /** The device supports the WPA1 encryption/authentication protocol. */ WPA, /** The device supports the WPA2/RSN encryption/authentication protocol. */ RSN, /** The device supports Access Point mode. */ AP, /** The device supports Ad-Hoc mode. */ ADHOC, /** The device reports frequency capabilities. */ FREQ_VALID, /** The device supports 2.4GHz frequencies. */ FREQ_2GHZ, /** The device supports 5GHz frequencies. */ FREQ_5GHZ, /** The device supports mesh points. */ MESH, /** The device supports WPA2 in IBSS networks */ IBSS_RSN; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiChannel.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; import java.util.Objects; import java.util.Optional; import org.osgi.annotation.versioning.ProviderType; /** * This class represent a WiFi channel, providing the channel number, frequency, * status and other useful informations. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class WifiChannel { private final int channel; private final int frequency; private final Optional disabled; private final Optional attenuation; private final Optional noInitiatingRadiation; private final Optional radarDetection; private WifiChannel(Builder builder) { this.channel = builder.channel; this.frequency = builder.frequency; this.disabled = builder.disabled; this.attenuation = builder.attenuation; this.noInitiatingRadiation = builder.noInitiatingRadiation; this.radarDetection = builder.radarDetection; } public int getChannel() { return this.channel; } public int getFrequency() { return this.frequency; } public Optional getAttenuation() { return this.attenuation; } public Optional getNoInitiatingRadiation() { return this.noInitiatingRadiation; } public Optional getRadarDetection() { return this.radarDetection; } public Optional getDisabled() { return this.disabled; } @Override public int hashCode() { return Objects.hash(this.attenuation, this.channel, this.disabled, this.frequency, this.noInitiatingRadiation, this.radarDetection); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } WifiChannel other = (WifiChannel) obj; return Objects.equals(this.attenuation, other.attenuation) && this.channel == other.channel && Objects.equals(this.disabled, other.disabled) && this.frequency == other.frequency && Objects.equals(this.noInitiatingRadiation, other.noInitiatingRadiation) && Objects.equals(this.radarDetection, other.radarDetection); } public static Builder builder(final int channel, final int frequency) { return new Builder(channel, frequency); } public static final class Builder { private int channel; private int frequency; private Optional disabled = Optional.empty(); private Optional attenuation = Optional.empty(); private Optional noInitiatingRadiation = Optional.empty(); private Optional radarDetection = Optional.empty(); private Builder(final int channel, final int frequency) { this.channel = channel; this.frequency = frequency; } public Builder withChannel(int channel) { this.channel = channel; return this; } public Builder withFrequency(int frequency) { this.frequency = frequency; return this; } public Builder withDisabled(final boolean disabled) { this.disabled = Optional.of(disabled); return this; } public Builder withAttenuation(final float attenuation) { this.attenuation = Optional.of(attenuation); return this; } public Builder withNoInitiatingRadiation(final boolean noInitiatingRadiation) { this.noInitiatingRadiation = Optional.of(noInitiatingRadiation); return this; } public Builder withRadarDetection(final boolean radarDetection) { this.radarDetection = Optional.of(radarDetection); return this; } public WifiChannel build() { return new WifiChannel(this); } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiFlag.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; /** * Flags describing the capabilities of an Access Point. * * @since 2.8 */ public enum WifiFlag { /** None */ NONE, /** Supports authentication and encryption */ PRIVACY, /** Supports WPS */ WPS, /** Supports push-button based WPS */ WPS_PBC, /** Supports PIN based WPS */ WPS_PIN; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiInterfaceStatus.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.osgi.annotation.versioning.ProviderType; /** * Class that contains specific properties to describe the status of a * WiFi interface. * */ @ProviderType public class WifiInterfaceStatus extends NetworkInterfaceStatus { private final Set capabilities; private final List channels; private final String countryCode; private final WifiMode mode; private final Optional activeWifiAccessPoint; private final List availableWifiAccessPoints; private WifiInterfaceStatus(WifiInterfaceStatusBuilder builder) { super(builder); this.capabilities = builder.capabilities; this.channels = builder.channels; this.countryCode = builder.countryCode; this.mode = builder.mode; this.activeWifiAccessPoint = builder.currentWifiAccessPoint; this.availableWifiAccessPoints = builder.availableWifiAccessPoints; } public Set getCapabilities() { return this.capabilities; } public List getChannels() { return this.channels; } public String getCountryCode() { return this.countryCode; } public WifiMode getMode() { return this.mode; } public Optional getActiveWifiAccessPoint() { return this.activeWifiAccessPoint; } public List getAvailableWifiAccessPoints() { return this.availableWifiAccessPoints; } public static WifiInterfaceStatusBuilder builder() { return new WifiInterfaceStatusBuilder(); } public static class WifiInterfaceStatusBuilder extends NetworkInterfaceStatusBuilder { private Set capabilities = EnumSet.of(WifiCapability.NONE); private List channels = Collections.emptyList(); private String countryCode = "00"; private WifiMode mode = WifiMode.UNKNOWN; private Optional currentWifiAccessPoint = Optional.empty(); private List availableWifiAccessPoints = Collections.emptyList(); public WifiInterfaceStatusBuilder withCapabilities(Set capabilities) { this.capabilities = capabilities; return this; } public WifiInterfaceStatusBuilder withWifiChannels(List channels) { this.channels = channels; return this; } public WifiInterfaceStatusBuilder withCountryCode(String countryCode) { this.countryCode = countryCode; return this; } public WifiInterfaceStatusBuilder withMode(WifiMode mode) { this.mode = mode; return this; } public WifiInterfaceStatusBuilder withActiveWifiAccessPoint(Optional currentWifiAccessPoint) { this.currentWifiAccessPoint = currentWifiAccessPoint; return this; } public WifiInterfaceStatusBuilder withAvailableWifiAccessPoints( List availableWifiAccessPoints) { this.availableWifiAccessPoints = availableWifiAccessPoints; return this; } @Override public WifiInterfaceStatus build() { withType(NetworkInterfaceType.WIFI); return new WifiInterfaceStatus(this); } @Override public WifiInterfaceStatusBuilder getThis() { return this; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + Objects.hash(this.activeWifiAccessPoint, this.availableWifiAccessPoints, this.capabilities, this.countryCode, this.mode, this.channels); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj) || getClass() != obj.getClass()) { return false; } WifiInterfaceStatus other = (WifiInterfaceStatus) obj; return Objects.equals(this.activeWifiAccessPoint, other.activeWifiAccessPoint) && Objects.equals(this.availableWifiAccessPoints, other.availableWifiAccessPoints) && Objects.equals(this.capabilities, other.capabilities) && Objects.equals(this.countryCode, other.countryCode) && this.mode == other.mode && Objects.equals(this.channels, other.channels); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiMode.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; /** * Modes of operation for WiFi interfaces */ public enum WifiMode { /** Mode is unknown. */ UNKNOWN, /** Uncoordinated network without central infrastructure. */ ADHOC, /** Client mode - Coordinated network with one or more central controllers. */ INFRA, /** * Access Point Mode - Coordinated network with one or more central controllers. */ MASTER, /** IEEE 802.11s mesh network. */ MESH; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiRadioMode.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; /** * Types of WiFi radio modes */ public enum WifiRadioMode { UNKNOWN, RADIO_MODE_80211A, RADIO_MODE_80211B, RADIO_MODE_80211G, RADIO_MODE_80211NHT20, RADIO_MODE_80211NHT40_BELOW, RADIO_MODE_80211NHT40_ABOVE, RADIO_MODE_80211_AC; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/WifiSecurity.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.status.wifi; /** * Flags describing the security capabilities of an Access Point. */ public enum WifiSecurity { /** None */ NONE, /** Supports pairwise 40-bit WEP encryption. */ PAIR_WEP40, /** Supports pairwise 104-bit WEP encryption. */ PAIR_WEP104, /** Supports pairwise TKIP encryption. */ PAIR_TKIP, /** Supports pairwise CCMP encryption. */ PAIR_CCMP, /** Supports a group 40-bit WEP cipher. */ GROUP_WEP40, /** Supports a group 104-bit WEP cipher. */ GROUP_WEP104, /** Supports a group TKIP cipher. */ GROUP_TKIP, /** Supports a group CCMP cipher. */ GROUP_CCMP, /** Supports PSK key management. */ KEY_MGMT_PSK, /** Supports 802.1x key management. */ KEY_MGMT_802_1X, /** Supports WPA/RSN Simultaneous Authentication of Equals. */ KEY_MGMT_SAE, /** Supports WPA/RSN Opportunistic Wireless Encryption. */ KEY_MGMT_OWE, /** Supports WPA/RSN Opportunistic Wireless Encryption transition mode. */ KEY_MGMT_OWE_TM, /** Supports WPA3 Enterprise Suite-B 192 bit mode */ KEY_MGMT_EAP_SUITE_B_192; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/status/wifi/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides classes for describing the status of a WiFi interface. * */ package org.eclipse.kura.net.status.wifi; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/vlan/VlanInterface.java ================================================ /******************************************************************************* * Copyright (c) 2023 Areti and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Areti * Eurotech ******************************************************************************/ package org.eclipse.kura.net.vlan; import java.util.List; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.osgi.annotation.versioning.ProviderType; /** * Network interface for Vlans. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.6 */ @ProviderType public interface VlanInterface extends NetInterface { /** * Indicates Vlan configuration flags. * * @return */ public int getFlags(); /** * Indicates the underlying physical interface to the Vlan. * * @return */ public String getParentInterface(); /** * Indicates the configured Vlan tag. * * @return */ public int getVlanId(); /** * Indicates configured ingress priority map. * * @return */ public List getIngressMap(); /** * Indicates configured egress priority map. * * @return */ public List getEgressMap(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/vlan/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Areti and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Areti * Eurotech ******************************************************************************/ /** * Provides interfaces for instances and configurations of Vlan. * */ package org.eclipse.kura.net.vlan; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPoint.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.EnumSet; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * The WifiAccessPoint models an access point for a Wifi network. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WifiAccessPoint { /** * The Service Set Identifier identifying the access point. * * @return */ public String getSSID(); /** * The hardware address (BSSID) of the access point. * * @return */ public byte[] getHardwareAddress(); /** * The radio channel frequency in use by the access point, in MHz. * * @return */ public long getFrequency(); /** * * * The Wi-Fi channel number in use by the access point. * * @return Wi-Fi channel number * @since 2.2 */ public int getChannel(); /** * * * Describes the operating mode of the access point. * * @return */ public WifiMode getMode(); /** * The bitrates this access point is capable of, in kilobits/second (Kb/s). * * @return */ public List getBitrate(); /** * The current signal quality of the access point, in percent. * * @return */ public int getStrength(); /** * Describes the access point's capabilities according to WPA (Wifi Protected Access). * * @return */ public EnumSet getWpaSecurity(); /** * Describes the access point's capabilities according to the RSN (Robust Secure Network) protocol. * * @return */ public EnumSet getRsnSecurity(); /** * Describes the access point's capabilities * * @return */ public List getCapabilities(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPointAddedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Emitted when a new access point is found by the device. * * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class WifiAccessPointAddedEvent extends Event { /** Topic of the WifiAccessPointAddedEvent */ public static final String NETWORK_EVENT_ACCESSPOINT_ADDED_TOPIC = "org/eclipse/kura/net/NetworkEvent/AccessPoint/ADDED"; /** Name of the property to access the network interface name */ public static final String NETWORK_EVENT_INTERFACE_PROPERTY = "network.interface"; /** Name of the property to access the access point */ public static final String NETWORK_EVENT_ACCESS_POINT_PROPERTY = "network.access.point"; public WifiAccessPointAddedEvent(Map properties) { super(NETWORK_EVENT_ACCESSPOINT_ADDED_TOPIC, properties); } /** * Returns the network interface name. * * @return */ public String getInterfaceName() { return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY); } /** * Returns the name of the added access point. * * @return */ public WifiAccessPoint getAccessPoint() { return (WifiAccessPoint) getProperty(NETWORK_EVENT_ACCESS_POINT_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiAccessPointRemovedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * Emitted when an access point disappears from view of the device. * * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class WifiAccessPointRemovedEvent extends Event { /** Topic of the WifiAccessPointAddedEvent */ public static final String NETWORK_EVENT_ACCESSPOINT_REMOVED_TOPIC = "org/eclipse/kura/net/NetworkEvent/AccessPoint/REMOVED"; /** Name of the property to access the network interface name */ public static final String NETWORK_EVENT_INTERFACE_PROPERTY = "network.interface"; /** Name of the property to access the access point */ public static final String NETWORK_EVENT_ACCESS_POINT_PROPERTY = "network.access.point"; public WifiAccessPointRemovedEvent(Map properties) { super(NETWORK_EVENT_ACCESSPOINT_REMOVED_TOPIC, properties); } /** * Returns the network interface name. * * @return */ public String getInterfaceName() { return (String) getProperty(NETWORK_EVENT_INTERFACE_PROPERTY); } /** * Returns the name of the removed access point. * * @return */ public WifiAccessPoint getAccessPoint() { return (WifiAccessPoint) getProperty(NETWORK_EVENT_ACCESS_POINT_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiBgscan.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import org.osgi.annotation.versioning.ProviderType; /** * Background Scan container class * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class WifiBgscan { private WifiBgscanModule module = null; private int shortInterval = 0; private int longInterval = 0; private int rssiThreshold = 0; public WifiBgscan(WifiBgscanModule module, int shortInterval, int rssiThreshold, int longInterval) { this.module = module; this.shortInterval = shortInterval; this.rssiThreshold = rssiThreshold; this.longInterval = longInterval; } public WifiBgscan(WifiBgscan bgscan) { this.module = bgscan.module; this.shortInterval = bgscan.shortInterval; this.rssiThreshold = bgscan.rssiThreshold; this.longInterval = bgscan.longInterval; } public WifiBgscan(String str) { if (str == null || str.length() == 0) { this.module = WifiBgscanModule.NONE; } else { String[] sa = str.split(":"); if (sa[0].equals("simple")) { this.module = WifiBgscanModule.SIMPLE; } else if (sa[0].equals("learn")) { this.module = WifiBgscanModule.LEARN; } this.shortInterval = Integer.parseInt(sa[1]); this.rssiThreshold = Integer.parseInt(sa[2]); this.longInterval = Integer.parseInt(sa[3]); } } public WifiBgscanModule getModule() { return this.module; } public int getShortInterval() { return this.shortInterval; } public int getLongInterval() { return this.longInterval; } public int getRssiThreshold() { return this.rssiThreshold; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.longInterval; result = prime * result + (this.module == null ? 0 : this.module.hashCode()); result = prime * result + this.rssiThreshold; result = prime * result + this.shortInterval; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } WifiBgscan other = (WifiBgscan) obj; if (this.longInterval != other.longInterval) { return false; } if (this.module != other.module) { return false; } if (this.rssiThreshold != other.rssiThreshold) { return false; } if (this.shortInterval != other.shortInterval) { return false; } return true; } /* * (non-Javadoc) * * @see java.lang.Object#toString() */ @Override public String toString() { StringBuffer sb = new StringBuffer(); if (this.module == WifiBgscanModule.SIMPLE) { sb.append("simple:"); } else if (this.module == WifiBgscanModule.LEARN) { sb.append("learn:"); } else { sb.append(""); return sb.toString(); } sb.append(this.shortInterval); sb.append(':'); sb.append(this.rssiThreshold); sb.append(':'); sb.append(this.longInterval); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiBgscanModule.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; /** * Module for background scan */ public enum WifiBgscanModule { NONE(0x00), SIMPLE(0x01), LEARN(0x02); private int code; private WifiBgscanModule(int code) { this.code = code; } public static WifiBgscanModule parseCode(int code) { for (WifiBgscanModule module : WifiBgscanModule.values()) { if (module.code == code) { return module; } } return null; } public static int getCode(WifiBgscanModule modules) { for (WifiBgscanModule module : WifiBgscanModule.values()) { if (module == modules) { return module.code; } } return -1; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiChannel.java ================================================ /******************************************************************************* * Copyright (c) 2021 Sterwen-Technology and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Sterwen-Technology * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.Objects; import org.osgi.annotation.versioning.ProviderType; /** * Wifi channel and Frequency in MHz * * @since 2.2 * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class WifiChannel { /** Wifi channel **/ private Integer channel; /** Wifi frequency in MHz **/ private Integer frequency; private Float attenuation; private Boolean noInitiatingRadiation; private Boolean radarDetection; private Boolean disabled; public WifiChannel(int channel, Integer frequency) { this.channel = channel; this.frequency = frequency; } public Integer getChannel() { return channel; } public void setChannel(Integer channel) { this.channel = channel; } public Integer getFrequency() { return frequency; } public void setFrequency(Integer frequency) { this.frequency = frequency; } /** * @since 2.3 */ public Boolean isNoInitiatingRadiation() { return noInitiatingRadiation; } /** * @since 2.3 */ public void setNoInitiatingRadiation(Boolean noInitiatingRadiation) { this.noInitiatingRadiation = noInitiatingRadiation; } /** * @since 2.3 */ public Boolean isRadarDetection() { return radarDetection; } /** * @since 2.3 */ public void setRadarDetection(Boolean radarDetection) { this.radarDetection = radarDetection; } /** * @since 2.3 */ public Boolean isDisabled() { return disabled; } /** * @since 2.3 */ public void setDisabled(Boolean disabled) { this.disabled = disabled; } /** * @since 2.3 */ public Float getAttenuation() { return attenuation; } /** * @since 2.3 */ public void setAttenuation(Float attenuation) { this.attenuation = attenuation; } @Override public int hashCode() { return Objects.hash(channel, frequency); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } WifiChannel other = (WifiChannel) obj; return Objects.equals(channel, other.channel) && Objects.equals(frequency, other.frequency); } @Override public String toString() { return "WifiChannel [channel=" + channel + ", frequency=" + frequency + ", attenuation=" + attenuation + ", noInitiatingRadiation=" + noInitiatingRadiation + ", radarDetection=" + radarDetection + ", disabled=" + disabled + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiCiphers.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; /** * Wifi Ciphers enum */ public enum WifiCiphers { CCMP_TKIP(0x00), TKIP(0x01), CCMP(0x02); private int code; private WifiCiphers(int code) { this.code = code; } public static WifiCiphers parseCode(int code) { for (WifiCiphers cipher : WifiCiphers.values()) { if (cipher.code == code) { return cipher; } } return null; } public static int getCode(WifiCiphers ciphers) { for (WifiCiphers cipher : WifiCiphers.values()) { if (cipher == ciphers) { return cipher.code; } } return -1; } public static String toString(WifiCiphers ciphers) { String ret = null; for (WifiCiphers cipher : WifiCiphers.values()) { if (cipher == ciphers) { if (cipher == WifiCiphers.CCMP_TKIP) { ret = "CCMP TKIP"; } else if (cipher == WifiCiphers.TKIP) { ret = "TKIP"; } else if (cipher == WifiCiphers.CCMP) { ret = "CCMP"; } } } return ret; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiClientMonitorListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import org.osgi.annotation.versioning.ConsumerType; /** * @deprecated since 3.0 */ @ConsumerType @Deprecated public interface WifiClientMonitorListener { /** * @since 2.0 */ public void setWifiSignalLevel(String interfaceName, int signalLevel); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiClientMonitorService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Marker interface for wifi client monitoring service * * @noimplement This interface is not intended to be implemented by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public interface WifiClientMonitorService { public void registerListener(WifiClientMonitorListener listener); public void unregisterListener(WifiClientMonitorListener listener); /** * Return the signal level on the given wireless interface * * @param interfaceName * the name of the wireless interface * @param ssid * the name of the ssid the interface is attached to * @return an integer number representing the rssi * @throws KuraException * * @deprecated since 2.4. Use {@link getSignalLevel(String interfaceName, String * ssid, boolean recompute)} instead. */ @Deprecated public int getSignalLevel(String interfaceName, String ssid) throws KuraException; /** * Return the signal level on the given wireless interface * * @param interfaceName * the name of the wireless interface * @param ssid * the name of the ssid the interface is attached to * @param recompute * if set to true, the rssi is recomputed. Otherwise a * cached value is returned * @return an integer number representing the rssi * @throws KuraException * * @since 2.4 */ public int getSignalLevel(String interfaceName, String ssid, boolean recompute) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Sterwen-Technology ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.net.NetConfig; import org.osgi.annotation.versioning.ProviderType; /** * Configuration for a wifi interface based on IPv4 addresses. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class WifiConfig implements NetConfig { /** Mode for the configuration **/ private WifiMode mode; /** SSID of the the wifi interface **/ private String ssid; /** Channel(s) supported by the wifi interface **/ private int[] channels; /** Security mode of the interface **/ private WifiSecurity security; /** Supported pairwise ciphers **/ private WifiCiphers pairwiseCiphers; /** Supported group ciphers **/ private WifiCiphers groupCiphers; /** The passkey for the wifi interface **/ private Password passkey; /** The hardware mode **/ private String hwMode; /** Radio mode **/ private WifiRadioMode radioMode; /** Background scan **/ private WifiBgscan bgscan; /** Ping Access Point **/ private boolean pingAccessPoint = false; /** Ignore SSID **/ private boolean ignoreSSID; /** The driver of the wifi interface **/ private String driver; /** Channels Frequencies **/ List channelFrequencies; /** Wifi Country Code **/ private String wifiCountryCode; public WifiConfig() { this(WifiMode.UNKNOWN, "", new int[] { 1 }, WifiSecurity.NONE, "", "b", null); } /** * @deprecated since 2.3. Use {@link WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security, * String passkey, String hwMode, WifiBgscan bgscan)} */ @SuppressWarnings("checkstyle:parameterNumber") @Deprecated public WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security, String passkey, String hwMode, boolean broadcast, WifiBgscan bgscan) { this(mode, ssid, channels, security, passkey, hwMode, bgscan); } /** * @since 2.3 * * @param mode * for the configuration as {@link WifiMode} * @param ssid * of the the wifi interface * @param channels * supported by the wifi interface * @param security * mode of the interface as {@link WifiSecurity} * @param passkey * for the wifi interface * @param hwMode * the hardware mode * @param bgscan * the background scan */ public WifiConfig(WifiMode mode, String ssid, int[] channels, WifiSecurity security, String passkey, String hwMode, WifiBgscan bgscan) { this.mode = mode; this.ssid = ssid; this.channels = channels; this.security = security; this.passkey = new Password(passkey); this.hwMode = hwMode; this.bgscan = bgscan; this.pairwiseCiphers = WifiCiphers.CCMP_TKIP; this.groupCiphers = WifiCiphers.CCMP_TKIP; this.radioMode = WifiRadioMode.RADIO_MODE_80211b; this.ignoreSSID = false; this.channelFrequencies = new ArrayList<>(); this.wifiCountryCode = "00"; } public WifiMode getMode() { return this.mode; } public void setMode(WifiMode mode) { this.mode = mode; } public String getSSID() { return this.ssid; } public void setSSID(String ssid) { this.ssid = ssid; } public String getDriver() { return this.driver; } public void setDriver(String driver) { this.driver = driver; } public int[] getChannels() { return this.channels; } public void setChannels(int[] channels) { this.channels = channels; } public WifiSecurity getSecurity() { return this.security; } public void setSecurity(WifiSecurity security) { this.security = security; } public WifiCiphers getPairwiseCiphers() { return this.pairwiseCiphers; } public void setPairwiseCiphers(WifiCiphers pairwise) { this.pairwiseCiphers = pairwise; } public WifiCiphers getGroupCiphers() { return this.groupCiphers; } public void setGroupCiphers(WifiCiphers group) { this.groupCiphers = group; } public Password getPasskey() { return this.passkey; } public void setPasskey(String key) { if (key != null) { Password psswd = new Password(key); this.passkey = psswd; } } public String getHardwareMode() { return this.hwMode; } public void setHardwareMode(String hwMode) { this.hwMode = hwMode; } public WifiRadioMode getRadioMode() { return this.radioMode; } public void setRadioMode(WifiRadioMode radioMode) { this.radioMode = radioMode; } /** * @deprecated since 2.3 */ @Deprecated public boolean getBroadcast() { return false; } /** * @deprecated since 2.3 */ @Deprecated public void setBroadcast(boolean broadcast) { // Do nothing... } public WifiBgscan getBgscan() { return this.bgscan; } public void setBgscan(WifiBgscan bgscan) { this.bgscan = bgscan; } public boolean pingAccessPoint() { return this.pingAccessPoint; } public void setPingAccessPoint(boolean pingAP) { this.pingAccessPoint = pingAP; } public boolean ignoreSSID() { return this.ignoreSSID; } public void setIgnoreSSID(boolean ignoreSSID) { this.ignoreSSID = ignoreSSID; } /** * Get the Wi-Fi country code * * @return Wi-Fi country code in ISO 3166-1 alpha-2 * @since 2.2 */ public String getWifiCountryCode() { return this.wifiCountryCode; } /** * Set the Wi-Fi country code * * @param wifiCountryCode * Wi-Fi Country code in ISO 3166-1 alpha-2 format * @since 2.2 */ public void setWifiCountryCode(String wifiCountryCode) { this.wifiCountryCode = wifiCountryCode; } /** * Get the list of Wi-Fi channels and frequencies * * @return List of Wi-Fi channels and frequencies * @since 2.2 */ public List getChannelFrequencies() { return this.channelFrequencies; } /** * Set the list of channel frequencies * * @param channelFrequencies * list of Wi-Fi channels and relative frequencies * @since 2.2 */ public void setChannelFrequencies(List channelFrequencies) { this.channelFrequencies = channelFrequencies; } @Override public int hashCode() { final int prime = 29; int result = super.hashCode(); result = prime * result + (this.mode == null ? 0 : this.mode.hashCode()); result = prime * result + (this.ssid == null ? 0 : this.ssid.hashCode()); result = prime * result + (this.driver == null ? 0 : this.driver.hashCode()); result = prime * result + (this.wifiCountryCode == null ? 0 : this.wifiCountryCode.hashCode()); if (this.channels != null) { for (int channel : this.channels) { result = prime * result + channel; } } else { result = prime * result; } if (this.channelFrequencies != null) { for (WifiChannel wc : this.channelFrequencies) { result = prime * result + wc.hashCode(); } } else { result = prime * result; } result = prime * result + (this.security == null ? 0 : this.security.hashCode()); result = prime * result + (this.passkey == null ? 0 : this.passkey.hashCode()); result = prime * result + (this.hwMode == null ? 0 : this.hwMode.hashCode()); result = prime * result + (this.radioMode == null ? 0 : this.radioMode.hashCode()); result = prime * result + (this.pairwiseCiphers == null ? 0 : WifiCiphers.getCode(this.pairwiseCiphers)); result = prime * result + (this.groupCiphers == null ? 0 : WifiCiphers.getCode(this.groupCiphers)); if (this.bgscan != null) { result = prime * result + (this.bgscan.getModule() == null ? 0 : WifiBgscanModule.getCode(this.bgscan.getModule())); result = prime * result + this.bgscan.getRssiThreshold(); result = prime * result + this.bgscan.getShortInterval(); result = prime * result + this.bgscan.getLongInterval(); } else { result = prime * result; } result = prime * result + (this.pingAccessPoint ? 1 : 0); result = prime * result + (this.ignoreSSID ? 1 : 0); return result; } @Override public boolean equals(Object obj) { if (!(obj instanceof WifiConfig)) { return false; } WifiConfig other = (WifiConfig) obj; if (!compare(this.mode, other.mode) || !compare(this.ssid, other.ssid) || !compare(this.driver, other.driver) || !Arrays.equals(this.channels, other.channels)) { return false; } if (!compare(this.wifiCountryCode, other.wifiCountryCode)) { return false; } if (!compare(this.security, other.security)) { return false; } if (!compare(this.pairwiseCiphers, other.pairwiseCiphers)) { return false; } if (!compare(this.groupCiphers, other.groupCiphers)) { return false; } if (!compare(this.passkey.toString(), other.passkey.toString())) { return false; } if (!compare(this.hwMode, other.hwMode)) { return false; } if (!compare(this.radioMode, other.radioMode)) { return false; } if (!compare(this.bgscan, other.bgscan)) { return false; } if (this.pingAccessPoint != other.pingAccessPoint()) { return false; } if (this.ignoreSSID != other.ignoreSSID()) { return false; } return true; } private boolean compare(Object obj1, Object obj2) { return obj1 == null ? obj2 == null : obj1.equals(obj2); } @Override public boolean isValid() { return this.mode != null; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("WifiConfig ["); if (this.mode != null) { sb.append("mode: ").append(this.mode).append(" :: "); } if (this.ssid != null) { sb.append("ssid: ").append(this.ssid).append(" :: "); } sb.append("ignoreSSID: ").append(this.ignoreSSID).append(" :: "); if (this.driver != null) { sb.append("driver: ").append(this.driver).append(" :: "); } if (this.channels != null && this.channels.length > 0) { sb.append("channels: "); for (int i = 0; i < this.channels.length; i++) { sb.append(this.channels[i]); if (i + i < this.channels.length) { sb.append(","); } } sb.append(" :: "); } if (this.security != null) { sb.append("security: ").append(this.security).append(" :: "); } if (this.pairwiseCiphers != null) { sb.append("pairwiseCiphers: ").append(this.pairwiseCiphers).append(" :: "); } if (this.groupCiphers != null) { sb.append("groupCiphers: ").append(this.groupCiphers).append(" :: "); } if (this.passkey != null) { sb.append("passkey: ").append(this.passkey).append(" :: "); } if (this.hwMode != null) { sb.append("hwMode: ").append(this.hwMode).append(" :: "); } if (this.radioMode != null) { sb.append("radioMode: ").append(this.radioMode).append(" :: "); } if (this.bgscan != null) { sb.append("bgscan: ").append(this.bgscan).append(" :: "); } if (this.wifiCountryCode != null) { sb.append("countryCode: ").append(this.wifiCountryCode).append(" :: "); } if (this.channelFrequencies != null) { sb.append("channelFrequencies: "); int i = 0; for (WifiChannel wc : this.channelFrequencies) { sb.append(wc); if (i++ != this.channelFrequencies.size() - 1) { sb.append(","); } } } sb.append("]"); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiHotspotInfo.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.EnumSet; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. * @deprecated since 3.0 */ @ProviderType @Deprecated public class WifiHotspotInfo { private final String ssid; private final String macAddress; private final int signalLevel; private final int channel; private final int frequency; private final WifiSecurity security; private EnumSet pairCiphers; private EnumSet groupCiphers; public WifiHotspotInfo(String ssid, String macAddress, int signalLevel, int channel, int frequency, WifiSecurity security) { super(); this.ssid = ssid; this.macAddress = macAddress; this.signalLevel = signalLevel; this.channel = channel; this.frequency = frequency; this.security = security; } @SuppressWarnings("checkstyle:parameterNumber") public WifiHotspotInfo(String ssid, String macAddress, int signalLevel, int channel, int frequency, WifiSecurity security, EnumSet pairCiphers, EnumSet groupCiphers) { this(ssid, macAddress, signalLevel, channel, frequency, security); this.pairCiphers = pairCiphers; this.groupCiphers = groupCiphers; } public String getSsid() { return this.ssid; } public String getMacAddress() { return this.macAddress; } public int getSignalLevel() { return this.signalLevel; } public int getChannel() { return this.channel; } public int getFrequency() { return this.frequency; } public WifiSecurity getSecurity() { return this.security; } public EnumSet getPairCiphers() { return this.pairCiphers; } public EnumSet getGroupCiphers() { return this.groupCiphers; } /** * @since 1.2 */ public void setPairCiphers(EnumSet pairCiphers) { this.pairCiphers = pairCiphers; } /** * @since 1.2 */ public void setGroupCiphers(EnumSet groupCiphers) { this.groupCiphers = groupCiphers; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(this.macAddress); sb.append(" :: "); sb.append(this.ssid); sb.append(" :: "); sb.append(this.signalLevel); sb.append(" :: "); sb.append(this.channel); sb.append(" :: "); sb.append(this.frequency); sb.append(" :: "); sb.append(this.security); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterface.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.List; import java.util.Set; import org.eclipse.kura.net.NetInterface; import org.osgi.annotation.versioning.ProviderType; /** * Wifi interface * * @param * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WifiInterface extends NetInterface { /** * Flags describing the capabilities of a wireless device. */ public enum Capability { /** no capabilities supported */ NONE, /** The device supports the 40-bit WEP cipher. */ CIPHER_WEP40, /** The device supports the 104-bit WEP cipher. */ CIPHER_WEP104, /** The device supports the TKIP cipher. */ CIPHER_TKIP, /** The device supports the CCMP cipher. */ CIPHER_CCMP, /** The device supports the WPA encryption/authentication protocol. */ WPA, /** The device supports the RSN encryption/authentication protocol. */ RSN, /** * The device supports the Automatic Channel Selection. * * @since 2.3 */ ACS, /** * The device supports the Dynamic Frequencies Selection. * * @since 2.3 */ DFS, /** * The device supports Very High Throughput. * * @since 2.3 */ VHT; } /** * Returns the the capabilities of the wireless device. * * @return * @since 2.0 */ public Set getCapabilities(); /** * Returns a List of all InterfaceAddresses of this network interface. * * @return a List object with all or a subset of the InterfaceAddresss of this network interface */ @Override public List getNetInterfaceAddresses(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterfaceAddress.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import org.eclipse.kura.net.NetInterfaceAddress; import org.osgi.annotation.versioning.ProviderType; /** * Interface for wifi status information * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WifiInterfaceAddress extends NetInterfaceAddress { /** * The operating mode of the wireless device. * * @return */ public WifiMode getMode(); /** * The bit rate currently used by the wireless device, in kilobits/second (Kb/s). * * @return */ public long getBitrate(); /** * Returns the WifiAccessPoint that this InterfaceAddress was acquired from when in managed mode. * Returns a WifiAccessPoint representing itself when in master mode. * * @return the WifiAccessPoint */ public WifiAccessPoint getWifiAccessPoint(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiInterfaceAddressConfig.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import java.util.List; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.NetInterfaceAddressConfig; import org.osgi.annotation.versioning.ProviderType; /** * Contains both the wifi interface status as well as all current configurations * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WifiInterfaceAddressConfig extends WifiInterfaceAddress, NetInterfaceAddressConfig { /** * Returns a List of NetConfig Objects associated with a given WifiInterfaceAddressConfig * for a given WifiInterface * * @return the NetConfig Objects associated with the WifiInterfaceAddressConfig */ @Override public List getConfigs(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiMode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; /** * Modes of operation for wifi interfaces */ public enum WifiMode { /** Mode is unknown. */ UNKNOWN(0x00), /** Uncoordinated network without central infrastructure. */ ADHOC(0x01), /** Client mode - Coordinated network with one or more central controllers. */ INFRA(0x02), /** Access Point Mode - Coordinated network with one or more central controllers. */ MASTER(0x03); private int code; private WifiMode(int code) { this.code = code; } public static WifiMode parseCode(int code) { for (WifiMode mode : WifiMode.values()) { if (mode.code == code) { return mode; } } return null; } public static int getCode(WifiMode wifiMode) { for (WifiMode mode : WifiMode.values()) { if (mode == wifiMode) { return mode.code; } } return -1; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiPassword.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.Password; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class WifiPassword extends Password { /** * WifiPassword constructor * * @param password * - WiFi password as {@link String} */ public WifiPassword(String password) { super(password); } /** * WifiPassword constructor * * @param password * - - WiFi password as {@link char[]} */ public WifiPassword(char[] password) { super(password); } /** * Validates WiFi password * * @param wifiSecurity * - WiFi security as {@link WifiSecurity} * @throws KuraException */ public void validate(WifiSecurity wifiSecurity) throws KuraException { if (getPassword() == null) { throw KuraException.internalError("the passwd can not be null"); } String passKey = new String(getPassword()).trim(); if (wifiSecurity == WifiSecurity.SECURITY_WEP) { if (passKey.length() == 10) { // check to make sure it is all hex try { Long.parseLong(passKey, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } } else if (passKey.length() == 26) { String part1 = passKey.substring(0, 13); String part2 = passKey.substring(13); try { Long.parseLong(part1, 16); Long.parseLong(part2, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } } else if (passKey.length() == 32) { String part1 = passKey.substring(0, 10); String part2 = passKey.substring(10, 20); String part3 = passKey.substring(20); try { Long.parseLong(part1, 16); Long.parseLong(part2, 16); Long.parseLong(part3, 16); } catch (Exception e) { throw KuraException.internalError( "the WEP key (passwd) must be all HEX characters (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, and f"); } } else if (!(passKey.length() == 5 || passKey.length() == 13 || passKey.length() == 16)) { // not 5, 13, or 16 ASCII characters throw KuraException .internalError("the WEP key (passwd) must be 10, 26, or 32 HEX characters in length"); } } else if (wifiSecurity == WifiSecurity.SECURITY_WPA || wifiSecurity == WifiSecurity.SECURITY_WPA2 || wifiSecurity == WifiSecurity.SECURITY_WPA_WPA2) { if (passKey.length() < 8 || passKey.length() > 63) { throw KuraException.internalError( "the WPA passphrase (passwd) must be between 8 (inclusive) and 63 (inclusive) characters in length: " + passKey); } } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiRadioMode.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; /** * Types of wifi radio modes */ public enum WifiRadioMode { RADIO_MODE_80211a(0x00), RADIO_MODE_80211b(0x01), RADIO_MODE_80211g(0x02), RADIO_MODE_80211nHT20(0x03), RADIO_MODE_80211nHT40below(0x04), RADIO_MODE_80211nHT40above(0x05), /** * @since 2.3 */ RADIO_MODE_80211_AC(0x06); private int code; private WifiRadioMode(int code) { this.code = code; } public static WifiRadioMode parseCode(int code) { for (WifiRadioMode mode : WifiRadioMode.values()) { if (mode.code == code) { return mode; } } return null; } public static int getCode(WifiRadioMode radioMode) { for (WifiRadioMode mode : WifiRadioMode.values()) { if (mode == radioMode) { return mode.code; } } return -1; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/WifiSecurity.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.net.wifi; /** * Flags describing the security capabilities of an access point. */ public enum WifiSecurity { /** None */ NONE(0x0), /** Supports pairwise 40-bit WEP encryption. */ PAIR_WEP40(0x1), /** Supports pairwise 104-bit WEP encryption. */ PAIR_WEP104(0x2), /** Supports pairwise TKIP encryption. */ PAIR_TKIP(0x4), /** Supports pairwise CCMP encryption. */ PAIR_CCMP(0x8), /** Supports a group 40-bit WEP cipher. */ GROUP_WEP40(0x10), /** Supports a group 104-bit WEP cipher. */ GROUP_WEP104(0x20), /** Supports a group TKIP cipher. */ GROUP_TKIP(0x40), /** Supports a group CCMP cipher. */ GROUP_CCMP(0x80), /** Supports PSK key management. */ KEY_MGMT_PSK(0x100), /** Supports 802.1x key management. */ KEY_MGMT_802_1X(0x200), /** Supports no encryption. */ SECURITY_NONE(0x400), /** Supports WEP encryption. */ SECURITY_WEP(0x800), /** Supports WPA encryption. */ SECURITY_WPA(0x1000), /** Supports WPA2 encryption. */ SECURITY_WPA2(0x2000), /** Supports WPA and WPA2 encryption. */ SECURITY_WPA_WPA2(0x4000), /** Supports WPA2 WPA3 enterprise. */ SECURITY_WPA2_WPA3_ENTERPRISE(0x8000), /** * @since 3.0 * Supports WPA3 encryption. */ SECURITY_WPA3(0x10000), /** * @since 3.0 * Supports WPA2 and WPA3 encryption. */ SECURITY_WPA2_WPA3(0x20000); private int code; private WifiSecurity(int code) { this.code = code; } public static WifiSecurity parseCode(int code) { for (WifiSecurity mode : WifiSecurity.values()) { if (mode.code == code) { return mode; } } return null; } public static int getCode(WifiSecurity security) { for (WifiSecurity mode : WifiSecurity.values()) { if (mode == security) { return mode.code; } } return -1; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/net/wifi/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides interfaces for instances and configurations of wifi devices. * */ package org.eclipse.kura.net.wifi; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal * *******************************************************************************/ /** * Contains the necessary classes for the framework related exceptions and error codes */ package org.eclipse.kura; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/GNSSType.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import java.util.HashMap; import java.util.Map; public enum GNSSType { UNKNOWN("Unknown"), OTHER("Other"), BEIDOU("Beidou"), GALILEO("Galileo"), GLONASS("Glonass"), GPS("Gps"), IRNSS("IRNSS"), QZSS("QZSS"); private String value; private static Map valuesMap = new HashMap<>(); static { for (GNSSType type : GNSSType.values()) { valuesMap.put(type.getValue(), type); } } private GNSSType(String value) { this.value = value; } public String getValue() { return this.value; } public static GNSSType fromValue(String value) { return valuesMap.get(value); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/NmeaPosition.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import org.osgi.annotation.versioning.ProviderType; /** * The NmeaPosition class is similar to org.osgi.util.position.Position but with different units * and more fields.
* The following fields are equivalent to org.osgi.util.position.Position fields but in more typical * units (degrees instead of radians): *

    *
  • Longitude in degrees *
  • Latitude in degrees *
  • Track in degrees *
  • Altitude in meters *
  • Speed in m/s (this field has different getters to retrieved value in m/s, km/h or mph) *
* It adds to the OSGI Position class the following fields:
*
    *
  • Fix Quality (from GPGGA) *
  • Number of Satellites (from GPGGA) *
  • DOP : Horizontal dilution of position (from GPGGA) *
  • 3D fix (from GPGSA) *
  • PRNs of sats used for fix (from GPGSA) *
  • PDOP : Dilution of precision (from GPGSA) *
  • HDOP : Horizontal Dilution of precision (from GPGSA) *
  • VDOP : Vertical Dilution of precision (from GPGSA) *
  • validFix : indicator of fix validity = A:active or V:void *
  • latitudeHemisphere : hemisphere of the latitude = N or S *
  • longitudeHemisphere : hemisphere of the longitude = E or W *
* * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class NmeaPosition { private static final double MS_TO_KMH = 3.6; private static final double MS_TO_MPH = 2.24; private double latitudeDegrees; private double longitudeDegrees; private double altitudeMeters; private double speedMetersPerSecond; private double trackDegrees; private int fixQuality; private int nrSatellites; private double mDOP; private double mPDOP; private double mHDOP; private double mVDOP; private int m3Dfix; private char validFix; private char latitudeHemisphere; private char longitudeHemisphere; public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees) { this(latDegrees, lonDegrees, altDegrees, speedMps, trackDegrees, 0, 0, 0.0, 0.0, 0.0, 0.0, 0, '0', '0', '0'); } @SuppressWarnings("checkstyle:parameterNumber") public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees, int fixQuality, int nrSatellites, double dop, double pdop, double hdop, double vdop, int fix3D) { this(latDegrees, lonDegrees, altDegrees, speedMps, trackDegrees, fixQuality, nrSatellites, dop, pdop, hdop, vdop, fix3D, '0', '0', '0'); } /** * @since 2.0 */ @SuppressWarnings("checkstyle:parameterNumber") public NmeaPosition(double latDegrees, double lonDegrees, double altDegrees, double speedMps, double trackDegrees, int fixQuality, int nrSatellites, double dop, double pdop, double hdop, double vdop, int fix3D, char validF, char hemiLat, char hemiLon) { this.latitudeDegrees = latDegrees; this.longitudeDegrees = lonDegrees; this.altitudeMeters = altDegrees; this.speedMetersPerSecond = speedMps; this.trackDegrees = trackDegrees; this.fixQuality = fixQuality; this.nrSatellites = nrSatellites; this.mDOP = dop; this.mPDOP = pdop; this.mHDOP = hdop; this.mVDOP = vdop; this.m3Dfix = fix3D; this.validFix = validF; this.latitudeHemisphere = hemiLat; this.longitudeHemisphere = hemiLon; } /** * Return the latitude in degrees */ public double getLatitude() { return this.latitudeDegrees; } public void setLatitude(double latitude) { this.latitudeDegrees = latitude; } /** * Return the longitude in degrees */ public double getLongitude() { return this.longitudeDegrees; } public void setLongitude(double longitude) { this.longitudeDegrees = longitude; } /** * Return the altitude in meters */ public double getAltitude() { return this.altitudeMeters; } public void setAltitude(double altitude) { this.altitudeMeters = altitude; } /** * Return the speed in km/h */ public double getSpeedKmh() { return this.speedMetersPerSecond * MS_TO_KMH; } /** * Return the speed in mph */ public double getSpeedMph() { return this.speedMetersPerSecond * MS_TO_MPH; } /** * Return the speed in m/s */ public double getSpeed() { return this.speedMetersPerSecond; } public void setSpeed(double speed) { this.speedMetersPerSecond = speed; } /** * Return the track in degrees */ public double getTrack() { return this.trackDegrees; } public void setTrack(double track) { this.trackDegrees = track; } public int getFixQuality() { return this.fixQuality; } public void setFixQuality(int fixQuality) { this.fixQuality = fixQuality; } public int getNrSatellites() { return this.nrSatellites; } public void setNrSatellites(int nrSatellites) { this.nrSatellites = nrSatellites; } public double getDOP() { return this.mDOP; } public void setDOP(double dop) { this.mDOP = dop; } public double getPDOP() { return this.mPDOP; } public void setPDOP(double pdop) { this.mPDOP = pdop; } public double getHDOP() { return this.mHDOP; } public void setHDOP(double hdop) { this.mHDOP = hdop; } public double getVDOP() { return this.mVDOP; } public void setVDOP(double vdop) { this.mVDOP = vdop; } public int get3Dfix() { return this.m3Dfix; } public void set3Dfix(int fix3D) { this.m3Dfix = fix3D; } /** * @since 2.0 */ public char getValidFix() { return this.validFix; } /** * @since 2.0 */ public void setValidFix(char validFix) { this.validFix = validFix; } /** * @since 2.0 */ public char getLatitudeHemisphere() { return this.latitudeHemisphere; } /** * @since 2.0 */ public void setLatitudeHemisphere(char latitudeHemisphere) { this.latitudeHemisphere = latitudeHemisphere; } /** * @since 2.0 */ public char getLongitudeHemisphere() { return this.longitudeHemisphere; } /** * @since 2.0 */ public void setLongitudeHemisphere(char longitudeHemisphere) { this.longitudeHemisphere = longitudeHemisphere; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionException.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class PositionException extends Exception { private static final long serialVersionUID = 2611760893640245224L; public PositionException() { // TODO Auto-generated constructor stub } public PositionException(String message) { super(message); // TODO Auto-generated constructor stub } public PositionException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } public PositionException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionListener.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import org.osgi.annotation.versioning.ConsumerType; @ConsumerType public interface PositionListener { public void newNmeaSentence(String nmeaSentence); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionLockedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * PositionLockedEvent is raised when a valid GPS position has been acquired. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class PositionLockedEvent extends Event { /** Topic of the PositionLockedEvent */ public static final String POSITION_LOCKED_EVENT_TOPIC = "org/eclipse/kura/position/locked"; public PositionLockedEvent(Map properties) { super(POSITION_LOCKED_EVENT_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionLostEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * PositionLostEvent is raised when GPS position has been lost. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class PositionLostEvent extends Event { /** Topic of the PositionLostEvent */ public static final String POSITION_LOST_EVENT_TOPIC = "org/eclipse/kura/position/lost"; public PositionLostEvent(Map properties) { super(POSITION_LOST_EVENT_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/PositionService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.position; import java.time.LocalDateTime; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; import org.osgi.util.position.Position; /** * This interface provides methods getting a geographic position. * The OSGI Position class represents a geographic location, based on the WGS84 System * (World Geodetic System 1984). *

* Position(Measurement lat, Measurement lon, Measurement alt, Measurement speed, Measurement track) *

* The interface also return a NmeaPosition, subclass of Position * * @see org.eclipse.kura.position.NmeaPosition NmeaPosition * @see org.osgi.util.position.Position Position * @see org.osgi.util.measurement.Measurement Measurement * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface PositionService { /** * Returns the current geographic position.
* The org.osgi.util.measurement.Measurement class is used to represent the values that make up a position: *

    *
  • getLongitude() : returns the longitude of this position in radians. Can be null. *
  • getLatitude() : returns the latitude of this position in radians. Can be null. *
  • getSpeed() : returns the ground speed of this position in meters per second. Can be null. *
  • getTrack() : Returns the track of this position in radians as a compass heading. The track is the * extrapolation of * previous previously measured positions to a future position. Can be null. *
* * @see org.osgi.util.position.Position Position */ public Position getPosition(); /** * Returns the current NMEA geographic position. *
    *
  • getLongitude() : returns the longitude of this position in degrees. *
  • getLatitude() : returns the latitude of this position in degrees. *
  • getSpeedKmh() : returns the ground speed of this position in km/h. *
  • getSpeedMph() : returns the ground speed of this position in mph. *
  • getTrack() : Returns the track of this position in degrees as a compass heading. *
* * @see org.eclipse.kura.position.NmeaPosition NmeaPosition * * @deprecated Since 2.3 use {@link #getPosition()}. Access to underlying gps data layer is discouraged. * */ @Deprecated public NmeaPosition getNmeaPosition(); /** * Returns the current NMEA time from GGA or ZDA sentence * * @throws UnsupportedOperetaionException * {@link PositionServiceProvider} could not support this method. * * @deprecated Since 2.3 use {@link #getDateTime()}. Access to underlying gps data layer is discouraged. * */ @Deprecated public String getNmeaTime(); /** * Returns the current NMEA date from ZDA sentence * * @throws UnsupportedOperetaionException * {@link PositionServiceProvider} could not support this method. * * @deprecated Since 2.3 use {@link #getDateTime()}. Access to underlying gps data layer is discouraged. * */ @Deprecated public String getNmeaDate(); /** * Returns the current date from {@link PositionServiceProvider}. Returned DateTime is in UTC TimeZone. * * @since 2.3 */ public LocalDateTime getDateTime(); /** * Returns true if a valid geographic position has been received. */ public boolean isLocked(); /** * @deprecated since version 2.3 * Returns the last sentence received from the gps. */ @Deprecated public String getLastSentence(); /** * Returns the GNSS System used to get the position information @reference GNSSType. Could be one or more system * (eg: GPS + GLONASS). * * If empty, no recognized GNSS System Type is available. * * @since 2.8 */ public Set getGnssTypes(); /** * Registers position listener * * @param listenerId * - listener ID as {@link String} * @param positionListener * - position listener as {@link PositionListener} */ public void registerListener(String listenerId, PositionListener positionListener); /** * Unregisters position listener * * @param listenerId * - listener ID as {@link String} */ public void unregisterListener(String listenerId); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/position/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains service to acquire global position. * */ package org.eclipse.kura.position; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/FloodingProtectionConfigurationChangeEvent.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security; import java.util.Map; import org.osgi.service.event.Event; /** * @since 2.2 */ public class FloodingProtectionConfigurationChangeEvent extends Event { public static final String FP_EVENT_CONFIG_CHANGE_TOPIC = "org/eclipse/kura/floodingprotection/event/FP_EVENT_CONFIG_CHANGE_TOPIC"; public FloodingProtectionConfigurationChangeEvent(Map properties) { super(FP_EVENT_CONFIG_CHANGE_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/FloodingProtectionConfigurationService.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security; import java.util.Set; import org.osgi.annotation.versioning.ProviderType; /** * This interface is used to provide the configuration for the flooding protection. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface FloodingProtectionConfigurationService { /** * Return a set of IPv4 firewall rules for the filter table needed to implement the flooding protection. * * @return the set of rules */ public Set getFloodingProtectionFilterRules(); /** * Return a set of IPv4 firewall rules for the nat table needed to implement the flooding protection. * * @return the set of rules */ public Set getFloodingProtectionNatRules(); /** * Return a set of IPv4 firewall rules for the mangle table needed to implement the flooding protection. * * @return the sets of rules */ public Set getFloodingProtectionMangleRules(); /** * Return a set of IPv6 firewall rules for the filter table needed to implement the flooding protection. * * @return the set of rules * @since 2.6 */ public Set getFloodingProtectionFilterRulesIPv6(); /** * Return a set of IPv6 firewall rules for the nat table needed to implement the flooding protection. * * @return the set of rules * @since 2.6 */ public Set getFloodingProtectionNatRulesIPv6(); /** * Return a set of IPv6 firewall rules for the mangle table needed to implement the flooding protection. * * @return the sets of rules * @since 2.6 */ public Set getFloodingProtectionMangleRulesIPv6(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/SecurityService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface SecurityService { /** * This method allows the reload of the security policy's fingerprint * * @throws KuraException * in case an error is raised during the calculation of the fingerprint and the consequent storage. */ public void reloadSecurityPolicyFingerprint() throws KuraException; /** * This method allows the reload of the command line fingerprint * * @throws KuraException * in case an error is raised during the calculation of the fingerprint and the consequent storage. */ public void reloadCommandLineFingerprint() throws KuraException; /** * This method returns a boolean that specifies if the debugging is permitted * * @return true if the debug is permitted. False otherwise. */ public boolean isDebugEnabled(); /** * This method allows to apply the default production security policy available in the system. The changes are * persistent and remain in effect after a framework restart. * * @throws KuraException * in case an error is raised during the application of the default production security policy. * @since 2.7 */ public void applyDefaultProductionSecurityPolicy() throws KuraException; /** * This method allows to apply the user provided security policy. The changes are persistent and remain in effect * after a framework restart. * * @param securityPolicy * the security policy to be applied * @throws KuraException * in case an error is raised during the application of the security policy. * @since 2.7 */ public void applySecurityPolicy(String securityPolicy) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/ThreatManagerService.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security; import org.osgi.annotation.versioning.ProviderType; /** * This marker interface is used to group the services that manage the network threats. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface ThreatManagerService { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreChangedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.security.keystore; import java.util.Collections; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * A OSGi EventAdmin Event sent to report a change in a keystore managed by a {@link KeystoreService}. * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public class KeystoreChangedEvent extends Event { /** * The EventAdmin topic of this event. */ public static final String EVENT_TOPIC = "org/eclipse/kura/security/keystore/KeystoreChangedEvent/KEYSTORE_CHANGED"; /** * The key of a Event property containing the kura.service.pid of the sender {@link KeystoreService} */ public static final String SENDER_PID_PROPERTY_KEY = "sender.pid"; public KeystoreChangedEvent(final String keystoreServicePid) { super(EVENT_TOPIC, Collections.singletonMap(SENDER_PID_PROPERTY_KEY, keystoreServicePid)); } /** * Returns the kura.service.pid of the sender {@link KeystoreService}. * * @return the kura.service.pid of the sender {@link KeystoreService}. */ public String getSenderPid() { return (String) getProperty(SENDER_PID_PROPERTY_KEY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.security.keystore; /** * Identifies a keystore with its name. * Further keystore information can be added (type, size...). * * @since 2.2 */ public class KeystoreInfo { private final String keystoreServicePid; private String type; private int size; public KeystoreInfo(String keystoreServicePid) { this.keystoreServicePid = keystoreServicePid; } public String getKeystoreServicePid() { return this.keystoreServicePid; } public String getType() { return this.type; } public void setType(String type) { this.type = type; } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/KeystoreService.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security.keystore; import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStore.Entry; import java.security.SecureRandom; import java.security.cert.CRL; import java.security.cert.CertStore; import java.security.cert.X509CRL; import java.security.spec.AlgorithmParameterSpec; import java.util.Collection; import java.util.List; import java.util.Map; import javax.net.ssl.KeyManager; import javax.security.auth.x500.X500Principal; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Provides a list of APIs useful to manage and abstract key objects and certificates * * @noimplement This interface is not intended to be implemented by clients. * @since 2.2 */ @ProviderType public interface KeystoreService { /** * Returns the managed {@link KeyStore} * * @return * @throws KuraException * when the keystore does not exist or cannot be loaded */ public KeyStore getKeyStore() throws KuraException; /** * Returns the entry object specified by the provided alias * * @param alias * @return * @throws KuraException * @throws IllegalArgumentException * if the specified alias is null */ public Entry getEntry(String alias) throws KuraException; /** * Stores the specified entry with the defined alias to the managed keystore * * @param alias * @param entry * @throws KuraException * if the entry could not be set or the keystore could not be persisted * @throws IllegalArgumentException * if one of the arguments is null */ public void setEntry(String alias, Entry entry) throws KuraException; /** * Returns the map representing the entries associated with the corresponding aliases in the keystore * * @return * @throws KuraException * if the entries could not be retrieved */ public Map getEntries() throws KuraException; /** * Deletes the entry identified by the specified alias, if it exists. * * @param alias * @throws KuraException * if the entry could not be deleted or the managed keystore could not be persisted after the change * @throws IllegalArgumentException * if the specified alias is null */ public void deleteEntry(String alias) throws KuraException; /** * Returns one key manager for each type of key material. * * @param algorithm * @return a list of key manager * @throws KuraException * if the provided algorithm is not supported or does not exist or if the associated keystore cannot be * accessed * @throws IllegalArgumentException * if the algorithm is null */ public List getKeyManagers(String algorithm) throws KuraException; /** * Returns one key manager for each type of key material using the Java Security API Provider matching the given name. * * @param algorithm * @param provider * the name of the Provider to be used * @return a list of key manager * @throws KuraException * if the provided algorithm/provider is not supported or does not exist or if the associated keystore * cannot be * accessed * @throws IllegalArgumentException * if algorithm or provider is null * * @since 2.8 */ public List getKeyManagers(String algorithm, String provider) throws KuraException; /** * Creates and persists a new keypair in the managed keystore using the specified alias. * * @param alias * @param algorithm * @param keySize * @param signatureAlgorithm * @param attributes * @throws KuraException * if the keypair cannot be created or the keypair cannot be added to the managed keystore * @throws IllegalArgumentException * if one of the arguments is null or empty */ public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes) throws KuraException; /** * Creates and persists a new keypair in the managed keystore using the specified alias. * * @param alias * @param algorithm * @param keySize * @param signatureAlgorithm * @param attributes * @param secureRandom * @throws KuraException * if the keypair cannot be created or the keypair cannot be added to the managed keystore * @throws IllegalArgumentException * if one of the arguments is null or empty */ public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException; /** * Creates and persists a new keypair in the managed keystore using the specified alias. * * @param alias * a string that will be used to identify the certificate in a key store. * @param algorithm * a string indicating the algorithm used to generate the keypair. * @param algorithmParameter * a set of algorithm parameters passed to the keypair generator. * @param signatureAlgorithm * a string indicating the signature algorithm used to sign the certificate containing the generated * keypair. * @param attributes * a string representing the X.500 Distinguished Name to include in the generated certificate. * @param secureRandom * the RNG (Random Number Generator) to use in the keypair generator. * @throws KuraException * if the keypair cannot be created or the keypair cannot be added to the managed keystore * @throws IllegalArgumentException * if one of the arguments is null or empty * * @since 2.4 */ public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException; /** * Creates and persists a new keypair in the managed keystore using the specified alias. * * @param alias * a string that will be used to identify the certificate in a key store. * @param algorithm * a string indicating the algorithm used to generate the keypair. * @param algorithmParameter * a set of algorithm parameters passed to the keypair generator. * @param signatureAlgorithm * a string indicating the signature algorithm used to sign the certificate containing the generated * keypair. * @param attributes * a string representing the X.500 Distinguished Name to include in the generated certificate. * @throws KuraException * if the keypair cannot be created or the keypair cannot be added to the managed keystore * @throws IllegalArgumentException * if one of the arguments is null or empty * @since 2.4 */ public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes) throws KuraException; /** * Creates and returns a CSR for the given keypair based on the provided principal and signer algorithm selected. * * @param keyPair * a keypair holding the private and public key. * @param principal * an X500Name containing the subject associated with the request we are building. * @param signerAlg * a String representing the signer algorithm used to sign the certificate signing request. * @return the Certificate Signing Request in PEM format. * @throws KuraException * if the CSR cannot be computed or if it cannot be encoded * @throws IllegalArgumentException * if one of the arguments is null or empty */ public String getCSR(KeyPair keyPair, X500Principal principal, String signerAlg) throws KuraException; /** * Creates and returns a CSR for the given keypair based on the provided principal and signer algorithm selected. * * @param alias * a string that will be used to identify the entity in the keystore holding the private and public keys. * @param principal * an X500Name containing the subject associated with the request we are building. * @param signerAlg * a String representing the signer algorithm used to sign the certificate signing request. * @return the Certificate Signing Request in PEM format. * @throws KuraException * if the alias does not correspond to a managed entry of the keystore, it refers to an entry that * cannot be used to obtain a CSR or the CSR cannot be computed or encoded * @throws IllegalArgumentException * if one of the arguments is null or empty */ public String getCSR(String alias, X500Principal principal, String signerAlg) throws KuraException; /** * Returns the list of all the aliases corresponding to the keystore service managed objects * * @return * @throws KuraException * if the list of aliases cannot be retrieved */ public List getAliases() throws KuraException; /** * Returns a list of the current cached CRLs. * * @return a list of the current cached CRLs. * @throws KuraException * if the list cannot be retrieved */ public Collection getCRLs() throws KuraException; /** * Returns a CertStore containing the cached CRLs. * * @return a CertStore containing the cached CRLs. * @throws KuraException * if the CertStore cannot be created. */ public CertStore getCRLStore() throws KuraException; /** * Add a X509CRL to the CRLs list. * * @param crl * a X509CRL to be stored * @throws KuraException * if the X509CRL cannot be added. * * @since 2.4 */ public void addCRL(X509CRL crl) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/keystore/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides security related APIs for key management * */ package org.eclipse.kura.security.keystore; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides security related APIs * */ package org.eclipse.kura.security; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperDetectionProperties.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security.tamper.detection; import org.osgi.annotation.versioning.ProviderType; /** * Defines some well known keys for the properties returned by {@link TamperStatus#getProperties()}. * * @since 2.2 */ @ProviderType public enum TamperDetectionProperties { /** * Allows to specify a timestamp for the tamper event, if known. * The property value must be a long representing the UNIX timestamp of the event. */ TIMESTAMP_PROPERTY_KEY("timestamp"); private final String value; private TamperDetectionProperties(final String value) { this.value = value; } public String getValue() { return this.value; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperDetectionService.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security.tamper.detection; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * Specifies a service that implements tamper detection features. * This service introduces the concept of tamper status. The definition of tamper status depends on the implementation, * for example a device might be considered to be tampered if its external enclosure has been opened. * The tamper status is represented by the {@link TamperStatus} class. * The tamper status can be reset by calling the {@link TamperDetectionService#resetTamperStatus()} method. * This service must also generate {@link TamperEvent} EventAdmin events in particular conditions, see the corresponding * Javadoc for more details. * * @since 2.2 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface TamperDetectionService { /** * Returns an user friendly name describing this service. * * @return an user friendly name describing this service. */ public String getDisplayName(); /** * Returns the current {@link TamperStatus}. * * @return the current {@link TamperStatus}. * @throws KuraException * in case of an implementation failure in determining the tamper status. */ public TamperStatus getTamperStatus() throws KuraException; /** * Allows to reset the tamper state. After this method returns, the result of calling * {@link TamperDetectionService#getTamperStatus()} should have the tamper flag set to false, until the next tamper * event is detected. * * @throws KuraException * in case of reset implementation failure. */ public void resetTamperStatus() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperEvent.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security.tamper.detection; import static java.util.Objects.requireNonNull; import java.util.HashMap; import java.util.Map; import org.osgi.service.event.Event; /** * Represents a EventAdmin event that reports a change in tamper status. * The changes that can originate a {@link TamperEvent} are the following: * *
    *
  • The tamper status flag changes. This can happen because a tamper event has been detected by the implementation or * the tamper status has been reset by the user. In this case the implementation must send an event.
  • *
  • The tamper status properties change. In this case sending the event is optional.
  • *
* * This class contains a {@link TamperStatus} instance representing the new status. * * @since 2.2 * @noimplement This interface is not intended to be implemented by clients. */ public class TamperEvent extends Event { /** * The EventAdmin topic of this event. */ public static final String TAMPER_EVENT_TOPIC = "org/eclipse/kura/security/tamper/detection/TamperEvent/TAMPER_STATUS_CHANGED"; /** * The key of a Event property containing the new {@link TamperStatus} */ public static final String TAMPER_STATUS_PROPERTY_KEY = "tamper.status"; /** * The key of a Event property containing the kura.service.pid of the sender {@link TamperDetectionService} */ public static final String SENDER_PID_PROPERTY_KEY = "sender.pid"; /** * Creates a new {@link TamperEvent} instance. * * @param tamperDetectionKuraServicePid * the kura.service.pid of the sender {@link TamperDetectionService}. * * @param tamperStatus * the new {@link TamperStatus}, cannot be null. */ public TamperEvent(final String tamperDetectionServicePid, final TamperStatus tamperStatus) { super(TAMPER_EVENT_TOPIC, buildEventProperties(tamperDetectionServicePid, tamperStatus)); } /** * Returns the new {@link TamperStatus}. * * @return the new {@link TamperStatus}, cannot be null. */ public TamperStatus getTamperStatus() { return (TamperStatus) getProperty(TAMPER_STATUS_PROPERTY_KEY); } /** * Returns the kura.service.pid of the sender {@link TamperDetectionService}. * * @return the kura.service.pid of the sender {@link TamperDetectionService}. */ public String getSenderPid() { return (String) getProperty(SENDER_PID_PROPERTY_KEY); } private static Map buildEventProperties(final String tamperDetectionServicePid, final TamperStatus tamperStatus) { final Map properties = new HashMap<>(); properties.put(TAMPER_STATUS_PROPERTY_KEY, requireNonNull(tamperStatus, "Tamper status cannot be null")); properties.put(SENDER_PID_PROPERTY_KEY, requireNonNull(tamperDetectionServicePid, "Tamper detection service pid cannot be null")); return properties; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/TamperStatus.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.security.tamper.detection; import java.util.Collections; import java.util.Map; import org.eclipse.kura.type.TypedValue; import org.osgi.annotation.versioning.ProviderType; /** * Represents the device tamper status. * This includes a boolean flag that indicates if the device has been tampered or not and some properties. * The properties indicated in the {@link TamperDetectionProperties} enumeration are well known. * * @since 2.2 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public class TamperStatus { private final boolean isDeviceTampered; private final Map> properties; /** * Creates a new {@link TamperStatus} instance. * * @param isDeviceTampered * the current tamper status. * @param properties * the additional properties, can be null. */ public TamperStatus(boolean isDeviceTampered, Map> properties) { this.isDeviceTampered = isDeviceTampered; this.properties = properties != null ? Collections.unmodifiableMap(properties) : Collections.emptyMap(); } /** * Indicates if the device is tampered or not. * * @return a boolean indicating if the device is tampered or not */ public boolean isDeviceTampered() { return this.isDeviceTampered; } /** * Returns additional properties describing the tamper status. * * @return the additional properties, the result is never null but can be empty. */ public Map> getProperties() { return this.properties; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/security/tamper/detection/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Defines APIs for tamper detection. * * @since 2.2 */ package org.eclipse.kura.security.tamper.detection; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/SslManagerService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ssl; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import org.osgi.annotation.versioning.ProviderType; /** * The SslManagerService is responsible to manage the configuration of the SSL connections. * It provide APIs to manage the trust certificates and the private keys and public certificates * and enforces best practices that are not enabled by default in the Java VM. * For example, it enables Hostname Verification, disables the legacy SSL-2.0-compatible Client Hello, * and disable the Nagle algorithm. * Its implementation is configurable exposing the possibility to express the allowed SSL protocols, * the allowed cipher suites, and the location of the Trust Store and the Key Store files. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface SslManagerService { /** * Returns an SSLContext based on the current configuration of the SslManagerService and applying * best practices like Hostname Verification and disables the legacy SSL-2.0-compatible Client Hello.
* If the SslManagerService configuration contains a path to a custom Trust store, then it will be used. * If not, the Java VM default Trust Store will be used.
* If the SslManagerService configuration contains a path to a custom Key store, then it will be used. * If not, no Key store will be specified..
* * @return the SSLContext * @since 2.2 */ public SSLContext getSSLContext() throws GeneralSecurityException, IOException; /** * Returns an SSLContext based on the current configuration of the SslManagerService and applying * best practices like Hostname Verification and disables the legacy SSL-2.0-compatible Client Hello.
* If the SslManagerService configuration contains a path to a custom Trust store, then it will be used. * If not, the Java VM default Trust Store will be used.
* If the SslManagerService configuration contains a path to a custom Key store, and such store contains * a KeyEntry with the alias "keyAlias" then a KeyStore with the only such KeyEntry will be used. * If no custom store is configured or it does not contain the "keyAlias" specified, no Key store will be * specified..
* * @param keyAlias * alias of the entry in the KeyStore to be used for the returned SSLSocketFactory * @return the SSLContext * @since 2.2 */ public SSLContext getSSLContext(String keyAlias) throws GeneralSecurityException, IOException; /** * Shorthand for getSSLContext().getSocketFactory(). * * @return the SSLSocketFactory */ public SSLSocketFactory getSSLSocketFactory() throws GeneralSecurityException, IOException; /** * Shorthand for getSSLContext(String).getSocketFactory(). * * @param keyAlias * alias of the entry in the KeyStore to be used for the returned SSLSocketFactory * @return the SSLSocketFactory */ public SSLSocketFactory getSSLSocketFactory(String keyAlias) throws GeneralSecurityException, IOException; /** * Shorthand for getSSLContext(String, String, String, String, char[], String).getSocketFactory(). * * @param protocol * the protocol to use to initialize the SSLContext - e.g. TLSv1.2 * @param cipherSuites * allowed cipher suites for the returned SSLSocketFactory * @param trustStorePath * Location of the Java keystore file containing the collection of CA certificates trusted by this * application process (trust store). Key store type is expected to be JKS. * @param keyStorePath * Location of the Java keystore file containing an application process's own certificate and private * key. Key store type is expected to be JKS. * @param keyStorePassword * Password to access the private key from the keystore file. * @param keyAlias * alias of the entry in the KeyStore to be used for the returned SSLSocketFactory * @return the SSLSocketFactory * @deprecated The methods that allow to explicitly specify a keystore should not be used anymore. */ @Deprecated public SSLSocketFactory getSSLSocketFactory(String protocol, String cipherSuites, String trustStorePath, String keyStorePath, char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException; /** * Shorthand for getSSLContext(String, String, String, String, char[], String, boolean).getSocketFactory(). * * @param protocol * the protocol to use to initialize the SSLContext - e.g. TLSv1.2 * @param cipherSuites * allowed cipher suites for the returned SSLSocketFactory * @param trustStorePath * Location of the Java keystore file containing the collection of CA certificates trusted by this * application process (trust store). Key store type is expected to be JKS. * @param keyStorePath * Location of the Java keystore file containing an application process's own certificate and private * key. Key store type is expected to be JKS. * @param keyStorePassword * Password to access the private key from the keystore file. * @param keyAlias * alias of the entry in the KeyStore to be used for the returned SSLSocketFactory * @param hostnameVerification * enable server Hostname Verification * @return the SSLSocketFactory * @deprecated The methods that allow to explicitly specify a keystore should not be used anymore. */ @Deprecated public SSLSocketFactory getSSLSocketFactory(String protocol, String cipherSuites, String trustStorePath, String keyStorePath, char[] keyStorePassword, String keyAlias, boolean hostnameVerification) throws GeneralSecurityException, IOException; /** * Returns the X509 Certificates installed in the currently configured trust store. * If the SslManagerService configuration contains a path to a custom trust store, then the returned certificates * are the ones installed in such store. * Otherwise the default Java VM trust store will be listed. * * @return the X509Certificates * @deprecated */ @Deprecated public X509Certificate[] getTrustCertificates() throws GeneralSecurityException, IOException; /** * Installs the specified X509 certificate in the currently configured trust store. * If the SslManagerService configuration contains a path to a custom trust store, then the certificate will be * installed in such store. * Otherwise the certificate will be installed in the default Java VM trust store. * * @param x509crt * certificate to be installed * @deprecated */ @Deprecated public void installTrustCertificate(String alias, X509Certificate x509crt) throws GeneralSecurityException, IOException; /** * Deletes the X509 certificate with the specified Common Name (cn) from the currently configured trust store. * If the SslManagerService configuration contains a path to a custom trust store, then the certificate will be * deleted from such store. * Otherwise the certificate will be deleted from the default Java VM trust store. * * @param alias * @deprecated */ @Deprecated public void deleteTrustCertificate(String alias) throws GeneralSecurityException, IOException; /** * Installs a private key and the correspondent public certificate chains in the configured key store with the * defined alias. * * @param alias * that is a string that will be used to identify the certificates in the key store * @param privateKey * that represents PrivateKey object * @param password * that represents the password used to encode the keys in the key store * @param publicCerts * that represents an array of Certificate objects that contain the public certificate chain * @deprecated */ @Deprecated public void installPrivateKey(String alias, PrivateKey privateKey, char[] password, Certificate[] publicCerts) throws GeneralSecurityException, IOException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/SslServiceListener.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.ssl; import org.osgi.annotation.versioning.ConsumerType; /** * Listener interface to be implemented by applications that needs to be notified of events in the * {@link SslManagerService}. * All registered listeners are called synchronously by the {@link SslManagerService} at the occurrence of the event. * It expected that implementers of this interface do NOT perform long running tasks in the implementation of this * interface. */ @ConsumerType public interface SslServiceListener { /** * Notifies the {@link SslManagerService} has received a configuration update and it has applied the new * configuration */ public void onConfigurationUpdated(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/ssl/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides SSL-related APIs * */ package org.eclipse.kura.ssl; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.status; import org.osgi.annotation.versioning.ConsumerType; /** * This interface must be implemented by classes which want to trigger a status change on the * {@link CloudConnectionStatusService} */ @ConsumerType public interface CloudConnectionStatusComponent { /** * Returns the notification priority for this Component. Usually a constant.
* Priorities range from {@code Integer.MIN_VALUE} to {@code Integer.MAX_VALUE}.
*
* Several constants are available for most used priorities:
* * * * * * * * * * * * * * * * * * * * * * * * * * * *
{@code CloudConnectionStatusService.PRIORITY_MAX}Maximum priority
{@code CloudConnectionStatusService.PRIORITY_CRITICAL}400
{@code CloudConnectionStatusService.PRIORITY_HIGH}300
{@code CloudConnectionStatusService.PRIORITY_MEDIUM}200
{@code CloudConnectionStatusService.PRIORITY_LOW}100
{@code CloudConnectionStatusService.PRIORITY_MIN}Minimum priority
* * @return An Integer indicating the priority for this component */ public int getNotificationPriority(); /** * Invoked by {@link CloudConnectionStatusService} to retrieve the current {@link CloudConnectionStatusEnum} status * for this component * * @return {@link CloudConnectionStatusEnum} representing the current status of the component */ public CloudConnectionStatusEnum getNotificationStatus(); /** * Invoked internally by {@link CloudConnectionStatusService} to persist the status of the component * * @param status * New status of this component */ public void setNotificationStatus(CloudConnectionStatusEnum status); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusEnum.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.status; /** * Enum used to store the status of the notification for a {@link CloudConnectionStatusComponent} * */ public enum CloudConnectionStatusEnum { OFF, FAST_BLINKING, SLOW_BLINKING, HEARTBEAT, ON; /** * Delays in ms for Fast Blinking */ public static final int FAST_BLINKING_ON_TIME = 100; public static final int FAST_BLINKING_OFF_TIME = 100; /** * Delays in ms for Slow Blinking */ public static final int SLOW_BLINKING_ON_TIME = 300; public static final int SLOW_BLINKING_OFF_TIME = 300; /** * Delays in ms for Heartbeat */ public static final int HEARTBEAT_SYSTOLE_DURATION = 150; public static final int HEARTBEAT_DIASTOLE_DURATION = 150; public static final int HEARTBEAT_PAUSE_DURATION = 600; /** * Delay in ms for periodic check on fixed statuses (On, Off) */ public static final int PERIODIC_STATUS_CHECK_DELAY = 5000; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/CloudConnectionStatusService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.status; import org.osgi.annotation.versioning.ProviderType; /** * The CloudConnectionStatusService is responsible for updating the user on the connection status of the framework. * Default implementation will link the status to a LED or to the log file.
* The service stores an internal list of {@link CloudConnectionStatusComponent} which represents all the elements * that are responsible of notifying the connection status.
*
* * Each {@link CloudConnectionStatusComponent} is assigned with a priority and a status ( * {@link CloudConnectionStatusEnum}). * The Service shows the status of the highest priority CloudConnectionStatusComponent registered in the list.
*
* In order to use the service, a class must implement the {@link CloudConnectionStatusComponent} interface and register * itself in the Service component registry using the {@code register(CloudConnectionStatusComponent c)} method.
*
* Unregistering the class from the Service registry will trigger a status switch to the previous priority found in the * Service component registry.
*
* A call to {@code updateStatus(...)} will trigger an internal status change for the relevant component, and the * Service will trigger a status change for the highest priority component only if needed.
*
*

Default implementation

* The default implementation is a Factory Component. A new instance of a {@link CloudConnectionStatusService} will be * instantiated for each communication stack. * The default CloudConnectionStatusService will have its kura.service.pid equals to * org.eclipse.kura.status.CloudConnectionStatusService
* Subsequent Communication Stacks will instantiate a relevant CloudConnectionStatusService with the appropriate * postfix.
* e.g. The CloudConnectionStatusService for a Communication Stack generated by a * org.eclipse.kura.cloud.CloudService-foo will have its kura.service.pid equals to * org.eclipse.kura.status.CloudConnectionStatusService-foo
*
* Configuration for a specific CloudConnectionStatusService can be found in the kura.properties file.
* The configuration is defined by a key value pair, where key is a URL-like string defining the service, and value is * the entity responsible to show the Cloud Connection Status. * It can be either a LED, the system log or none. * Configuration for specific instances of the CloudConnectionStatusService is achieved by correctly formatting the * URL-like key.
* The default configuration is stored under the key ccs.status.notification.url
* Configuration for specific communication stacks include the stack postfix in the URL-like key.
*
* e.g. The key-value pair to link the CloudConnectionStatusService generated for the "foo" stack (see above) to LED * number 25 would be:
* ccs.status.notification.url.foo=ccs:led:25
* Same configuration, but linking the status to the system log, would be:
* ccs.status.notification.url.foo=ccs:log * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface CloudConnectionStatusService { /** * Maximum priority for the notification. There should be only one StatusDisplayComponent at the same time * using this priority. */ public static final int PRIORITY_MAX = Integer.MAX_VALUE; /** * Priorities are evaluated in ascending order. * The Service will use the status of the registered component with highest priority */ public static final int PRIORITY_CRITICAL = 400; public static final int PRIORITY_HIGH = 300; public static final int PRIORITY_MEDIUM = 200; public static final int PRIORITY_LOW = 100; /** * Minimum priority for the notification. There should be at least and only one StatusDisplayComponent at the same * time using this priority. */ public static final int PRIORITY_MIN = Integer.MIN_VALUE; /** * Registers a {@link CloudConnectionStatusComponent} in the component registry of the Service * * @param component * CloudConnectionStatusComponent to be registered in the registry */ public void register(CloudConnectionStatusComponent component); /** * Unregisters a {@link CloudConnectionStatusComponent} from the component registry of the Service * * @param component * CloudConnectionStatusComponent to be unregistered from the registry */ public void unregister(CloudConnectionStatusComponent component); /** * Updates the status of a {@link CloudConnectionStatusComponent} in the registry. * Implementation should also set the internal status of the CloudConnectionStatus component so to persist it. * * @param component * {@link CloudConnectionStatusComponent} for which the status has to be changed * @param status * {@link CloudConnectionStatusEnum} representing the new status of the component * @return false if an error occurs, true otherwise */ public boolean updateStatus(CloudConnectionStatusComponent component, CloudConnectionStatusEnum status); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/status/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides service to notify the status of the connection to the cloud. * */ package org.eclipse.kura.status; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/ExtendedProperties.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * Represents a set of properties that can be returned by custom {@link SystemService} implementations to provide * additional * informations about the system that are not specified by the {@link SystemService} interface. * The extended properties are organized in named groups, as specified by the {@link ExtendedPropertyGroup} * interface. * The number of returned groups, their names and contained property keys and values are not specified by Kura APIs. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public class ExtendedProperties { private final String version; private final List groups; /** * Creates a new {@link ExtendedProperties} instance. * * @param version * the version * @param groups * the property groups */ public ExtendedProperties(final String version, final List groups) { if (requireNonNull(version, "version cannot be null").trim().isEmpty()) { throw new IllegalArgumentException("version cannot be empty"); } this.version = version; this.groups = Collections.unmodifiableList(requireNonNull(groups, "groups cannot be null")); } /** * Returns the version * * @return the version */ public String getVersion() { return version; } /** * Returns the property group list * * @return the property group list */ public List getPropertyGroups() { return groups; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/ExtendedPropertyGroup.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; /** * Represents an extended property group. * An extended property group has a name and some properties. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @ProviderType public class ExtendedPropertyGroup { private final String name; private final Map properties; /** * Creates a new {@link ExtendedPropertyGroup} instance. * * @param name * the group name, must not be null or empty * @param properties * the property map, must not be null */ public ExtendedPropertyGroup(final String name, final Map properties) { if (requireNonNull(name, "name cannot be null").trim().isEmpty()) { throw new IllegalArgumentException("name cannot be empty"); } this.name = name; this.properties = Collections.unmodifiableMap(requireNonNull(properties, "properties cannot be null")); } /** * Returns the group name. * * @return the group name. */ public String getName() { return name; } /** * Returns the group properties. * * @return the group properties. */ public Map getProperties() { return properties; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/InternetConnectionStatus.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.system; /** * Represents the status of the internet connection. * * @since 3.0 */ public enum InternetConnectionStatus { UNAVAILABLE, IP_ONLY, FULL } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemAdminService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; import org.osgi.annotation.versioning.ProviderType; /** * Service to perform basic system tasks. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface SystemAdminService { /** * Gets the amount of time this device has been up in milliseconds. * * @return How long this device has been up in milliseconds. */ public String getUptime(); /** * Reboots the device. */ public void reboot(); /** * Synchronizes data on flash with memory. */ public void sync(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemResourceInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * Represents all the information needed to identify and represent a System Resource. * A System Resource is every package or component of the system where the framework is running. * This information, for example, can be used to create an inventory of the System Resources * installed in the host system running the framework. * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ @Immutable @ThreadSafe @ProviderType public class SystemResourceInfo { private final String name; private final String version; private final SystemResourceType type; /** * Creates a new {@link SystemResourceInfo} instance. * * @param name * a string representing the resource name */ public SystemResourceInfo(String name) { this(name, "Unknown", SystemResourceType.UNKNOWN); } /** * Creates a new {@link SystemResourceInfo} instance. * * @param name * a string representing the resource name * @param version * a string representing the resource version * @param type * a string representing the resource type */ public SystemResourceInfo(String name, String version, String type) { this(name, version, SystemResourceType.valueOf(type)); } /** * Creates a new {@link SystemResourceInfo} instance. * * @param name * a string representing the resource name * @param version * a string representing the resource version * @param type * a {@link SystemResourceType} representing the resource type */ public SystemResourceInfo(String name, String version, SystemResourceType type) { this.name = name; this.version = version; this.type = type; } /** * Returns the resource name * * @return the resource name */ public String getName() { return this.name; } /** * Returns the resource version * * @return the resource version */ public String getVersion() { return this.version; } /** * Returns the resource type * * @return the resource type as {@link SystemResourceType} */ public SystemResourceType getType() { return this.type; } /** * Returns the resource type * * @return the resource type as {@link String} */ public String getTypeString() { return this.type.toString(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemResourceType.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; /** * An enum representing the supported System Resource Types * * @noextend This class is not intended to be subclassed by clients. * @since 2.2 */ public enum SystemResourceType { BUNDLE, DP, RPM, DEB, DOCKER, /** * @since 2.4 */ CONTAINER_IMAGE, APK, UNKNOWN; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/SystemService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.system; import java.util.List; import java.util.Optional; import java.util.Properties; import org.eclipse.kura.KuraProcessExecutionErrorException; import org.osgi.annotation.versioning.ProviderType; import org.osgi.framework.Bundle; /** * Service to provide basic system information including Operating System * information, JVM information and filesystem information. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface SystemService { public static final String KURA_CONFIG = "kura.configuration"; public static final String KURA_PROPS_FILE = "kura.properties"; public static final String KURA_CUSTOM_CONFIG = "kura.custom.configuration"; public static final String KURA_CUSTOM_PROPS_FILE = "kura_custom.properties"; public static final String OS_CLOUDBEES = "Linux (Cloudbees)"; public static final String OS_LINUX = "Linux"; public static final String OS_MAC_OSX = "Mac OS X"; public static final String UNKNOWN = "UNKNOWN"; public static final String UNSUPPORTED = "UNSUPPORTED"; public static final String KEY_KURA_NAME = "kura.name"; public static final String KEY_KURA_VERSION = "kura.version"; /** * @since 2.2 */ public static final String KEY_KURA_NET_VIRTUAL_DEVICES_CONFIG = "kura.net.virtual.devices.config"; /** * @since 2.0 */ public static final String KEY_KURA_FRAMEWORK_CONFIG_DIR = "kura.framework.config"; /** * @since 2.0 */ public static final String KEY_KURA_USER_CONFIG_DIR = "kura.user.config"; /** * @since 1.3 */ public static final String KEY_KURA_MARKETPLACE_COMPATIBILITY_VERSION = "kura.marketplace.compatibility.version"; public static final String KEY_DEVICE_NAME = "kura.device.name"; public static final String KEY_PLATFORM = "kura.platform"; public static final String KEY_MODEL_ID = "kura.model.id"; public static final String KEY_MODEL_NAME = "kura.model.name"; public static final String KEY_PART_NUMBER = "kura.partNumber"; public static final String KEY_SERIAL_NUM = "kura.serialNumber"; public static final String KEY_BIOS_VERSION = "kura.bios.version"; public static final String KEY_FIRMWARE_VERSION = "kura.firmware.version"; public static final String KEY_PRIMARY_NET_IFACE = "kura.primary.network.interface"; public static final String KEY_KURA_HOME_DIR = "kura.home"; public static final String KEY_KURA_PLUGINS_DIR = "kura.plugins"; /** * @since 1.2 */ public static final String KEY_KURA_PACKAGES_DIR = "kura.packages"; public static final String KEY_KURA_DATA_DIR = "kura.data"; public static final String KEY_KURA_TMP_DIR = "kura.tmp"; public static final String KEY_KURA_SNAPSHOTS_DIR = "kura.snapshots"; public static final String KEY_KURA_SNAPSHOTS_COUNT = "kura.snapshots.count"; public static final String KEY_KURA_HAVE_NET_ADMIN = "kura.have.net.admin"; public static final String KEY_KURA_HAVE_WEB_INTER = "kura.have.web.inter"; public static final String KEY_KURA_STYLE_DIR = "kura.style.dir"; public static final String KEY_KURA_WIFI_TOP_CHANNEL = "kura.wifi.top.channel"; public static final String KEY_KURA_KEY_STORE_PWD = "kura.ssl.keyStorePassword"; public static final String KEY_KURA_TRUST_STORE_PWD = "kura.ssl.trustStorePassword"; public static final String KEY_FILE_COMMAND_ZIP_MAX_SIZE = "file.command.zip.max.size"; public static final String KEY_FILE_COMMAND_ZIP_MAX_NUMBER = "file.command.zip.max.number"; public static final String KEY_OS_ARCH = "os.arch"; public static final String KEY_OS_NAME = "os.name"; public static final String KEY_OS_VER = "os.version"; public static final String KEY_OS_DISTRO = "os.distribution"; public static final String KEY_OS_DISTRO_VER = "os.distribution.version"; public static final String KEY_JAVA_VERSION = "java.runtime.version"; public static final String KEY_JAVA_VENDOR = "java.runtime.name"; public static final String KEY_JAVA_VM_NAME = "java.vm.name"; public static final String KEY_JAVA_VM_VERSION = "java.vm.version"; public static final String KEY_JAVA_VM_INFO = "java.vm.info"; public static final String KEY_OSGI_FW_NAME = "org.osgi.framework.vendor"; public static final String KEY_OSGI_FW_VERSION = "org.osgi.framework.version"; public static final String KEY_JAVA_HOME = "java.home"; public static final String KEY_FILE_SEP = "file.separator"; public static final String CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE = "console.device.management.service.ignore"; /** * @since 2.2 */ public static final String KEY_COMMAND_USER = "kura.command.user"; /** * @since 2.2 */ public static final String KEY_CPU_VERSION = "cpu.version"; /** * @since 2.2 */ public static final String KEY_LEGACY_BT_BEACON_SCAN = "kura.legacy.bluetooth.beacon.scan"; /** * @since 2.3 */ public static final String KEY_LEGACY_PPP_LOGGING = "kura.legacy.ppp.logging.enabled"; /** * @since 2.6 */ public static final String KEY_JAVA_VM_VENDOR = "java.vm.vendor"; /** * @since 2.6 */ public static final String KEY_JDK_VENDOR_VERSION = "jdk.vendor.version"; /** * @since 2.8 */ public static final String KEY_DEFAULT_LOG_MANAGER = "kura.default.log.manager"; /** * @since 3.0 */ public static final String KEY_WPA3_WIFI_SECURITY_ENABLE = "kura.wpa3.wifi.security.enable"; /** * @since 3.0 */ public static final String KEY_NETWORK_CONFIGURATION_TIMEOUT = "kura.network.configuration.timeout"; /** * @since 3.0 Hostname used to verify internet connection status. */ public static final String KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST = "kura.internet.check.hostname"; /** * @since 3.0 Address in a format according to system IP version available (e.g. 198.41.30.198 in IPv4 or * ::ffff:c629:1ec6 in IPv6) required to verify the internet connection status. * In order to use the functionality, an IPv6-only system must override this property with an IPv6 address. */ public static final String KEY_INTERNET_CONNECTION_STATUS_CHECK_IP = "kura.internet.check.ip"; /** * @deprecated */ @Deprecated public static final String DB_URL_PROPNAME = "db.service.hsqldb.url"; /** * @deprecated */ @Deprecated public static final String DB_WRITE_DELAY_MILLIES_PROPNAME = "db.service.hsqldb.write_delay_millis"; /** * @deprecated */ @Deprecated public static final String DB_LOG_DATA_PROPNAME = "db.service.hsqldb.log_data"; /** * @deprecated */ @Deprecated public static final String DB_CACHE_ROWS_PROPNAME = "db.service.hsqldb.cache_rows"; /** * @deprecated */ @Deprecated public static final String DB_LOB_FILE_PROPNAME = "db.service.hsqldb.lob_file_scale"; /** * @deprecated */ @Deprecated public static final String DB_DEFRAG_LIMIT_PROPNAME = "db.service.hsqldb.defrag_limit"; /** * @deprecated */ @Deprecated public static final String DB_LOG_SIZE_PROPNAME = "db.service.hsqldb.log_size"; /** * @deprecated */ @Deprecated public static final String DB_NIO_PROPNAME = "db.service.hsqldb.nio_data_file"; /** * Gets the primary MAC address of the system * * @return */ public String getPrimaryMacAddress(); /** * Gets the name of the 'primary' network interface. * * @return */ public String getPrimaryNetworkInterfaceName(); /** * Gets the platform name Kura is running on. This could be catalyst, duracor1200, helios, isis, proteus, etc. * * @return The platform name. */ public String getPlatform(); /** * Gets the model identification of the device. * * @return Model ID. */ public String getModelId(); /** * Gets the model name of the device. * * @return Model name. */ public String getModelName(); /** * Gets the part number. * * @return Part number. */ public String getPartNumber(); /** * Gets the serial number of the device. * * @return Serial number. */ public String getSerialNumber(); /** * Returns a friendly name assigned to this device. * * @return */ public String getDeviceName(); /** * Gets the BIOS version of the device. * * @return BIOS version. */ public String getBiosVersion(); /** * Gets the firmware version. * * @return Firmware version. */ public String getFirmwareVersion(); /** * Gets the Operating System architecture for the system. * * @return The Operating System architecture as defined by the Java System property os.arch. */ public String getOsArch(); /** * Gets the Operating System name for the system. * * @return The Operating System name as defined by the Java System property os.name. */ public String getOsName(); /** * Gets the Operating System version for the system. * * @return The Operating System version as defined by the Java System property os.version. */ public String getOsVersion(); /** * Gets the Operating System Distribution name if appropriate. * * @return A String representing the Operating System Distribution name if appropriate. */ public String getOsDistro(); /** * Gets the Operating System Distribution version if appropriate. * * @return A String representing the Operating System Distribution version if appropriate. */ public String getOsDistroVersion(); /** * Gets the vendor of the Java VM that is currently being used. * * @return The Java Runtime version as defined by the Java System property java.vendor. */ public String getJavaVendor(); /** * Gets the Java version that is currently being used. * * @return The Java version as defined by the Java System property java.version. */ public String getJavaVersion(); /** * Gets the Java Virtual Machine name that is currently being used. * * @return The Java Virtual Machine name as defined by the Java System property java.vm.name. */ public String getJavaVmName(); /** * Gets the Java Virtual Machine version that is currently being used. * * @return The Java Virtual Machine version as defined by the Java System property java.vm.version. */ public String getJavaVmVersion(); /** * Gets the Java Virtual Machine information that is currently being used. * Indicates if virtual machine was built with just-in-time-compiler support. * Values are "mixed mode" or "interpreter loop". * * @return The Java Virtual Machine version as defined by the Java System * property java.vm.info. */ public String getJavaVmInfo(); /** * Gets the name of the OSGI Framework that is currently being used. * * @return The OSGI Framework Name as defined by the System property osgi.framework.name. */ public String getOsgiFwName(); /** * Gets the version of the OSGI Framework that is currently being used. * * @return The OSGI Framework Version as defined by the System property osgi.framework.version. */ public String getOsgiFwVersion(); /** * Gets the system file separator used by the filesystem. * * @return The system file separator used by the system. */ public String getFileSeparator(); /** * Gets the location where the JVM is stored in the filesystem. * * @return The location of the root JVM directory. */ public String getJavaHome(); /** * Gets the product version for this unit. * * The product version is defined in the kura.version property of the kura.properties file * located in the ${BASE_DIR}/${KURA_SYMLINK}/kura directory. * * @return The Kura version string as denoted in kura.version property of the kura.properties file. */ public String getKuraVersion(); /** * Gets the location where Kura stores the framework configuration files in the filesystem. * * @since 2.0 * @return The framework configuration files directory. */ public String getKuraFrameworkConfigDirectory(); /** * Gets the location where Kura stores the user configuration files in the filesystem. * * @since 2.0 * @return The user configuration files directory. */ public String getKuraUserConfigDirectory(); /** * Gets the Eclipse Marketplace compatibility product version for this unit. * * The marketplace compatibility product version is defined in the {@code kura.marketplace.compatibility.version} * property of the kura.properties file located in the ${BASE_DIR}/${KURA_SYMLINK}/kura directory. * If the variable {@code kura.marketplace.compatibility.version} cannot be located, it defaults to the value * specified by {@link #getKuraVersion()}. * * @since 1.3 * @return The marketplace compatibility Kura version string. */ public String getKuraMarketplaceCompatibilityVersion(); /** * Gets the location where the Kura root directory is stored in the filesystem. * * @return The root Kura directory. */ public String getKuraHome(); /** * Gets the location where all volatile Kura specific configuration and status information should be stored. * * The convention for each bundle that has filesystem dependencies is for those filesystem components * to be stored in the configuration directory root followed by a file separator followed by the project * name that needs some configuration. This will keep separate configuration components tied to their * appropriate projects. * * @return The location of the volatile Kura configuration and status directory root. */ public String getKuraTemporaryConfigDirectory(); /** * Gets the location where all Configuration Snapshots will be stored. * It is recommended for this directory not to be volatile so that the configuration * information can survive reboots and service configuration can be restored. * * @return The location of the volatile Kura configuration and status directory root. */ public String getKuraSnapshotsDirectory(); /** * Returns the maximum number of snapshots to be retained in the file system. * When the maximum number is reached, a garbage collector will delete the older snapshots. * * @return maximum number of snapshots to be retained. */ public int getKuraSnapshotsCount(); /** * Gets the location where all custom style information is stored. * * @return The location of the custom style directory. */ public String getKuraStyleDirectory(); /** * Gets the last wifi channel allowed for this device. In the U.S. this should be * 11. In most of Europe this should be 13. * * @return The last wifi channel allowed for this device (usually 11 or 13) */ public int getKuraWifiTopChannel(); public String getKuraWebEnabled(); /** * Gets the location where all Kura persistent data should be stored. * * @return The location of the persistent Kura data directory root. */ public String getKuraDataDirectory(); /** * Returns the size in MegaBytes of the maximum file upload size permitted by the local file servlet * * @return The maximum size (in mega bytes) of files that can be uploaded using the command file upload function */ public int getFileCommandZipMaxUploadSize(); /** * Returns the maximum number of files that can be uploaded by the local file servlet * * @return The maximum number of files that can be uploaded using the command file upload function */ public int getFileCommandZipMaxUploadNumber(); /** * Returns all KuraProperties for this system. The returned instances is * initialized by loading the kura.properties file. Properties defined at * the System level - for example using the java -D command line flag - * are used to overwrite the values loaded from the kura.properties file * in a hierarchical configuration fashion. */ public Properties getProperties(); /** * Returns the OSGi bundles currently installed * * @return the list of the installed bundles */ public Bundle[] getBundles(); /** * Returns the system packages currently installed * * @return the list of the installed packages * @throws KuraProcessExecutionErrorException * @since 2.2 */ public List getSystemPackages() throws KuraProcessExecutionErrorException; /** * Returns the number of processors visible to this Java platform. * * @return */ public int getNumberOfProcessors(); /** * Returns the total memory visible to this Java instance in kilobytes. * * @return */ public long getTotalMemory(); /** * Returns the free memory for Java instance in kilobytes. * * @return */ public long getFreeMemory(); /** * Returns the password to access the private key from the keystore file. * * @return */ public char[] getJavaKeyStorePassword(); /** * Returns the password to unlock the trust store keystore file. * * @return */ public char[] getJavaTrustStorePassword(); /** * Returns a list of services that should be ignored by the Cloud services * * @return */ public List getDeviceManagementServiceIgnore(); /** * Returns the device hostname * * @return a String that represents the device hostname * @since 2.0 */ public String getHostname(); /** * Returns the default configuration for virtual network interfaces * * @return a String that represent the default configuration for virtual interfaces * @since 2.2 */ public String getNetVirtualDevicesConfig(); /** * Gets the user to be used for running commands. * * @since 2.2 * @return command user */ public String getCommandUser(); /** * Gets the CPU version of the device. * * @since 2.2 * @return CPU version */ public String getCpuVersion(); /** * Returns a set of {@link ExtendedProperties}. * * @since 2.2 * @return the extended properties, or empty if the SystemService implementation does not provide extended * properties. */ public Optional getExtendedProperties(); /** * Returns the configuration for the bluetooth beacon scan. * If true, the legacy "hcitool" is used for beacon scanning. * * @since 2.2 * @return if the legacy beacon scan has to be used */ public boolean isLegacyBluetoothBeaconScan(); /** * Returns true (default) if the PPP logging in separate log file in /var/log is enabled. * * @since 2.3 * @return true if separate log file in /var/log is required */ public boolean isLegacyPPPLoggingEnabled(); /** * Gets the Java Virtual Machine implementation vendor that is currently being * used. * * @since 2.6 * @return the Java Virtual Machine version as defined by the Java System * property java.vm.vendor. */ public String getJavaVmVendor(); /** * * * @since 2.6 * @return the String representing the Java System property jdk.vendor.version. */ public String getJdkVendorVersion(); /** * Returns the name of the default LogManager, if any. * * @since 2.8 * @return the optional default LogManager */ public Optional getDefaultLogManager(); /** * Returns true if the WPA3 WiFi Security is enabled on this device. * The default is false. * * @since 3.0 * @return true if the WPA3 WiFi Security is enabled */ public boolean isWPA3WifiSecurityEnabled(); /** * Returns the timeout in seconds used for applying a network configuration. * * @since 3.0 * @return the timeout value in seconds */ public int getNetworkConfigurationTimeout(); /** * Indicates whether or not the device is connected to the internet and the status. * The status is updated every 30 seconds and the verification process uses an ICMP request. * * @since 3.0 * @return the {@link InternetConnectionStatus} */ public InternetConnectionStatus getInternetConnectionStatus(); /** * Return the inet address used to check the internet connection. Must support ICMP protocol. * * @since 3.0 * @return the inet address used to check the internet connection. Default value is 198.41.30.198 (current * eclipse.org IP address, which may change over time; this value should be updated if the eclipse.org IP * changes) */ public String getInternetConnectionStatusCheckIp(); /** * Returns the hostname used to check the internet connection. Must support ICMP protocol. * * @since 3.0 * @return the hostname address used to check the internet connection. Default value is eclipse.org */ public String getInternetConnectionStatusCheckHost(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/system/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Contains services to get system information and perform basic system tasks. * */ package org.eclipse.kura.system; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/BooleanValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.BOOLEAN; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Boolean} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class BooleanValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final boolean value; /** * Instantiates a new boolean value. * * @param value * the value */ public BooleanValue(final boolean value) { this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return this.value == otherTypedValue.getValue() ? 0 : this.value ? 1 : -1; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final BooleanValue other = (BooleanValue) obj; if (this.value != other.value) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return BOOLEAN; } /** {@inheritDoc} */ @Override public Boolean getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.value ? 1231 : 1237); return result; } /** {@inheritDoc} */ @Override public String toString() { return "BooleanValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/ByteArrayValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.BYTE_ARRAY; import java.util.Arrays; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Byte[]} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class ByteArrayValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final byte[] value; /** * Instantiates a new byte array value. * * @param value * the value * @throws NullPointerException * if the argument is null */ public ByteArrayValue(final byte[] value) { requireNonNull(value, "Provided Typed Value cannot be null"); this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); final byte[] otherValue = otherTypedValue.getValue(); for (int i = 0, j = 0; i < this.value.length && j < otherValue.length; i++, j++) { final int a = this.value[i] & 0xff; final int b = otherValue[j] & 0xff; if (a != b) { return a - b; } } return this.value.length - otherValue.length; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final ByteArrayValue other = (ByteArrayValue) obj; if (!Arrays.equals(this.value, other.value)) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return BYTE_ARRAY; } /** {@inheritDoc} */ @Override public byte[] getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Arrays.hashCode(this.value); return result; } /** {@inheritDoc} */ @Override public String toString() { return "ByteArrayValue [value=" + Arrays.toString(this.value) + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/DataType.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; /** * This contains all the required data type constants required for representing * Java data types as {@link TypedValue} * * @since 1.2 */ public enum DataType { BOOLEAN, BYTE_ARRAY, DOUBLE, INTEGER, LONG, FLOAT, STRING; /** * Converts {@code stringDataType}, if possible, to the related {@link DataType}. * * @param stringDataType * String that we want to use to get the respective {@link DataType}. * @return a DataType that corresponds to the String passed as argument. * @throws IllegalArgumentException * if the passed string does not correspond to an existing {@link DataType}. */ public static DataType getDataType(String stringDataType) { if (INTEGER.name().equalsIgnoreCase(stringDataType)) { return INTEGER; } if (FLOAT.name().equalsIgnoreCase(stringDataType)) { return FLOAT; } if (DOUBLE.name().equalsIgnoreCase(stringDataType)) { return DOUBLE; } if (LONG.name().equalsIgnoreCase(stringDataType)) { return LONG; } if (BYTE_ARRAY.name().equalsIgnoreCase(stringDataType)) { return BYTE_ARRAY; } if (BOOLEAN.name().equalsIgnoreCase(stringDataType)) { return BOOLEAN; } if (STRING.name().equalsIgnoreCase(stringDataType)) { return STRING; } throw new IllegalArgumentException("Cannot convert to DataType"); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/DoubleValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.DOUBLE; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Double} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class DoubleValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final double value; /** * Instantiates a new double value. * * @param value * the value */ public DoubleValue(final double value) { this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return Double.valueOf(this.value).compareTo(otherTypedValue.getValue()); } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final DoubleValue other = (DoubleValue) obj; if (Double.doubleToLongBits(this.value) != Double.doubleToLongBits(other.value)) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return DOUBLE; } /** {@inheritDoc} */ @Override public Double getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; long temp; temp = Double.doubleToLongBits(this.value); result = prime * result + (int) (temp ^ temp >>> 32); return result; } /** {@inheritDoc} */ @Override public String toString() { return "DoubleValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/FloatValue.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.FLOAT; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Float} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class FloatValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final float value; /** * Instantiates a new {@link Float} value. * * @param value * the value */ public FloatValue(final float value) { this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return Float.valueOf(this.value).compareTo(otherTypedValue.getValue()); } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof FloatValue)) { return false; } FloatValue other = (FloatValue) obj; if (Float.floatToIntBits(this.value) != Float.floatToIntBits(other.value)) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return FLOAT; } /** {@inheritDoc} */ @Override public Float getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + Float.floatToIntBits(this.value); return result; } /** {@inheritDoc} */ @Override public String toString() { return "FloatValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/IntegerValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.INTEGER; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Integer} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class IntegerValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final int value; /** * Instantiates a new integer value. * * @param value * the value */ public IntegerValue(final int value) { this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return Integer.valueOf(this.value).compareTo(otherTypedValue.getValue()); } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final IntegerValue other = (IntegerValue) obj; if (this.value != other.value) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return INTEGER; } /** {@inheritDoc} */ @Override public Integer getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.value; return result; } /** {@inheritDoc} */ @Override public String toString() { return "IntegerValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/LongValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.LONG; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link Long} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class LongValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final long value; /** * Instantiates a new long value. * * @param value * the value */ public LongValue(final long value) { this.value = value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return Long.valueOf(this.value).compareTo(otherTypedValue.getValue()); } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final LongValue other = (LongValue) obj; if (this.value != other.value) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return LONG; } /** {@inheritDoc} */ @Override public Long getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (int) (this.value ^ this.value >>> 32); return result; } /** {@inheritDoc} */ @Override public String toString() { return "LongValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/StringValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.type.DataType.STRING; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.Nullable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; /** * This class represents a {@link String} value as a {@link TypedValue}. * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class StringValue implements TypedValue { /** * The actual contained value that will be represented as * {@link TypedValue}. */ private final String value; /** * Instantiates a new string value. * * @param value * the value */ public StringValue(@Nullable final String value) { this.value = value == null ? "" : value; } /** {@inheritDoc} */ @Override public int compareTo(final TypedValue otherTypedValue) { requireNonNull(otherTypedValue, "Typed Value cannot be null"); return this.value.compareTo(otherTypedValue.getValue()); } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final StringValue other = (StringValue) obj; if (this.value == null) { if (other.value != null) { return false; } } else if (!this.value.equals(other.value)) { return false; } return true; } /** {@inheritDoc} */ @Override public DataType getType() { return STRING; } /** {@inheritDoc} */ @Override public String getValue() { return this.value; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.value == null ? 0 : this.value.hashCode()); return result; } /** {@inheritDoc} */ @Override public String toString() { return "StringValue [value=" + this.value + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/TypedValue.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import org.osgi.annotation.versioning.ProviderType; /** * This interface wraps a Java data type with its represented value format * * @param * The Java Value Type to be represented * * @see TypedValues * @see BooleanValue * @see ByteArrayValue * @see FloatValue * @see DoubleValue * @see IntegerValue * @see StringValue * @see DataType * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface TypedValue extends Comparable> { /** * Returns the data type of the represented value * * @return the datatype as associated */ public DataType getType(); /** * Returns the actual value as represented * * @return the value as associated */ public T getValue(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/TypedValues.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.type; import java.util.Base64; import java.util.Base64.Decoder; import java.util.Objects; import org.eclipse.kura.annotation.Nullable; import org.osgi.annotation.versioning.ProviderType; /** * The Class TypedValues is an utility class to quickly create different * {@link TypedValue} * * @since 1.2 */ @ProviderType public final class TypedValues { private static final Decoder BASE64_DECODER = Base64.getDecoder(); private TypedValues() { // Static Factory Methods container. No need to instantiate. } /** * Creates new boolean value. * * @param value * the primitive boolean value * @return the boolean value represented as {@link TypedValue} */ public static BooleanValue newBooleanValue(final boolean value) { return new BooleanValue(value); } /** * Creates new byte array value. * * @param value * the primitive byte array value * @return the byte array value represented as {@link TypedValue} * @throws org.eclipse.kura.KuraRuntimeException * if the argument is null */ public static ByteArrayValue newByteArrayValue(final byte[] value) { return new ByteArrayValue(value); } /** * Creates new float value. * * @param value * the primitive float value * @return the float value represented as {@link TypedValue} */ public static FloatValue newFloatValue(final float value) { return new FloatValue(value); } /** * Creates new double value. * * @param value * the primitive double value * @return the double value represented as {@link TypedValue} */ public static DoubleValue newDoubleValue(final double value) { return new DoubleValue(value); } /** * Creates new integer value. * * @param value * the primitive integer value * @return the integer value represented as {@link TypedValue} */ public static IntegerValue newIntegerValue(final int value) { return new IntegerValue(value); } /** * Creates new long value. * * @param value * the primitive long value * @return the long value represented as {@link TypedValue} */ public static LongValue newLongValue(final long value) { return new LongValue(value); } /** * Creates new string value. * * @param value * the string value to be represented as {@link TypedValue} * @return the string value represented as {@link TypedValue} */ public static StringValue newStringValue(@Nullable final String value) { return new StringValue(value); } /** * Creates new TypedValue inferring the type from the argument. * * @param value * an object that needs to be represented as {@link TypedValue} * @return a {@link TypedValue} that represents the conversion of {@code value} * @throws IllegalArgumentException * if {@code value} cannot be represented as {@link TypedValue} */ public static TypedValue newTypedValue(final Object value) { if (value instanceof Boolean) { return newBooleanValue((Boolean) value); } else if (value instanceof byte[]) { return newByteArrayValue((byte[]) value); } else if (value instanceof Float) { return newFloatValue((Float) value); } else if (value instanceof Double) { return newDoubleValue((Double) value); } else if (value instanceof Integer) { return newIntegerValue((Integer) value); } else if (value instanceof Long) { return newLongValue((Long) value); } else if (value instanceof String) { return newStringValue((String) value); } throw new IllegalArgumentException("Cannot convert to TypedValue"); } /** * Parses a TypedValue of given type from a String. * * @param value * the String to be parsed into a {@link TypedValue} * @param type * the {@link DataType} of the returned {@link TypedValue} * @return a {@link TypedValue} that represents the conversion of {@code value} * @throws IllegalArgumentException * if {@code value} cannot be represented as {@link TypedValue} */ public static TypedValue parseTypedValue(final DataType type, final String value) { Objects.requireNonNull(value, "value cannot be null"); try { switch (type) { case BOOLEAN: return newBooleanValue(Boolean.parseBoolean(value)); case BYTE_ARRAY: return TypedValues.newByteArrayValue(BASE64_DECODER.decode(value)); case DOUBLE: return newDoubleValue(Double.parseDouble(value)); case FLOAT: return newFloatValue(Float.parseFloat(value)); case INTEGER: return newIntegerValue(Integer.parseInt(value)); case LONG: return newLongValue(Long.parseLong(value)); case STRING: return newStringValue(value); default: } } catch (Exception e) { } throw new IllegalArgumentException(value + " cannot be converted into a TypedValue of type " + type); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/type/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ /** * This package provides wrapper value types which represents actual Java value * types as {@link org.eclipse.kura.type.TypedValue} and all utility classes * comprising necessary static factory methods * * @since 1.0.10 */ package org.eclipse.kura.type; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/AbstractUsbDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * Base class for USB devices * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public abstract class AbstractUsbDevice implements UsbDevice { /** The vendor ID of the USB device **/ private final String vendorId; /** The product ID of the USB device **/ private final String productId; /** The manufacturer name **/ private final String manufacturerName; /** The product name **/ private final String productName; private final String usbBusNumber; private final String usbDevicePath; public AbstractUsbDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath) { this.vendorId = vendorId; this.productId = productId; this.manufacturerName = manufacturerName; this.productName = productName; this.usbBusNumber = usbBusNumber; this.usbDevicePath = usbDevicePath; } public AbstractUsbDevice(AbstractUsbDevice usbDevice) { this.vendorId = usbDevice.getVendorId(); this.productId = usbDevice.getProductId(); this.manufacturerName = usbDevice.getManufacturerName(); this.productName = usbDevice.getProductName(); this.usbBusNumber = usbDevice.getUsbBusNumber(); this.usbDevicePath = usbDevice.getUsbDevicePath(); } @Override public String getVendorId() { return this.vendorId; } @Override public String getProductId() { return this.productId; } @Override public String getManufacturerName() { return this.manufacturerName; } @Override public String getProductName() { return this.productName; } @Override public String getUsbBusNumber() { return this.usbBusNumber; } @Override public String getUsbDevicePath() { return this.usbDevicePath; } @Override public String getUsbPort() { StringBuilder sb = new StringBuilder(); sb.append(this.usbBusNumber).append("-").append(this.usbDevicePath); return sb.toString(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.manufacturerName == null ? 0 : this.manufacturerName.hashCode()); result = prime * result + (this.productId == null ? 0 : this.productId.hashCode()); result = prime * result + (this.productName == null ? 0 : this.productName.hashCode()); result = prime * result + (this.usbBusNumber == null ? 0 : this.usbBusNumber.hashCode()); result = prime * result + (this.usbDevicePath == null ? 0 : this.usbDevicePath.hashCode()); result = prime * result + (this.vendorId == null ? 0 : this.vendorId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } AbstractUsbDevice other = (AbstractUsbDevice) obj; if (this.manufacturerName == null) { if (other.manufacturerName != null) { return false; } } else if (!this.manufacturerName.equals(other.manufacturerName)) { return false; } if (this.productId == null) { if (other.productId != null) { return false; } } else if (!this.productId.equals(other.productId)) { return false; } if (this.productName == null) { if (other.productName != null) { return false; } } else if (!this.productName.equals(other.productName)) { return false; } if (this.usbBusNumber == null) { if (other.usbBusNumber != null) { return false; } } else if (!this.usbBusNumber.equals(other.usbBusNumber)) { return false; } if (this.usbDevicePath == null) { if (other.usbDevicePath != null) { return false; } } else if (!this.usbDevicePath.equals(other.usbDevicePath)) { return false; } if (this.vendorId == null) { if (other.vendorId != null) { return false; } } else if (!this.vendorId.equals(other.vendorId)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbBlockDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * Representation of a USB block device. This includes storage type USB devices. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbBlockDevice extends AbstractUsbDevice { private final String deviceNode; public UsbBlockDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath, String deviceNode) { super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath); this.deviceNode = deviceNode; } public String getDeviceNode() { return this.deviceNode; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (this.deviceNode == null ? 0 : this.deviceNode.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } UsbBlockDevice other = (UsbBlockDevice) obj; if (this.deviceNode == null) { if (other.deviceNode != null) { return false; } } else if (!this.deviceNode.equals(other.deviceNode)) { return false; } return true; } @Override public String toString() { return "UsbBlockDevice [getDeviceNode()=" + getDeviceNode() + ", getVendorId()=" + getVendorId() + ", getProductId()=" + getProductId() + ", getManufacturerName()=" + getManufacturerName() + ", getProductName()=" + getProductName() + ", getUsbBusNumber()=" + getUsbBusNumber() + ", getUsbDevicePath()=" + getUsbDevicePath() + ", getUsbPort()=" + getUsbPort() + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * Interface for all USB devices * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface UsbDevice { /** * The vendor ID of the device * * @return The vendor ID of the device */ public String getVendorId(); /** * The product ID of the device * * @return The product ID of the device */ public String getProductId(); /** * The manufacturer name of the device * * @return The manufacturer name of the device */ public String getManufacturerName(); /** * The product name of the device * * @return The product name of the device */ public String getProductName(); /** * The USB bus number of the device * * @return The USB bus number of the device */ public String getUsbBusNumber(); /** * The USB device path * * @return The USB device path */ public String getUsbDevicePath(); /** * The complete USB port (USB bus number plus USB device path) * * @return The complete USB port (USB bus number plus USB device path) */ public String getUsbPort(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceAddedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * An event raised when a new USB device has been added to the system. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbDeviceAddedEvent extends Event implements UsbDeviceEvent { /** Topic of the UsbDeviceAddedEvent */ public static final String USB_EVENT_DEVICE_ADDED_TOPIC = "org/eclipse/kura/usb/NetworkEvent/device/ADDED"; public UsbDeviceAddedEvent(Map properties) { super(USB_EVENT_DEVICE_ADDED_TOPIC, properties); } /** * Returns the name of the USB port. * * @return */ public String getUsbPort() { return (String) getProperty(USB_EVENT_USB_PORT_PROPERTY); } /** * Returns the name of the USB resource associated with this device. * * @return */ public String getUsbResource() { return (String) getProperty(USB_EVENT_RESOURCE_PROPERTY); } /** * Returns the name of the USB vendor ID associated with this device. * * @return */ public String getUsbVendorId() { return (String) getProperty(USB_EVENT_VENDOR_ID_PROPERTY); } /** * Returns the name of the USB product ID associated with this device. * * @return */ public String getUsbProductId() { return (String) getProperty(USB_EVENT_PRODUCT_ID_PROPERTY); } /** * Returns the name of the USB manufacturer name associated with this device. * * @return */ public String getUsbManufacturerName() { return (String) getProperty(USB_EVENT_MANUFACTURER_NAME_PROPERTY); } /** * Returns the name of the USB product name associated with this device. * * @return */ public String getUsbProductName() { return (String) getProperty(USB_EVENT_PRODUCT_NAME_PROPERTY); } /** * Returns the name of the USB bus number associated with this device. * * @return */ public String getUsbBusNumber() { return (String) getProperty(USB_EVENT_BUS_NUMBER_PROPERTY); } /** * Returns the name of the USB device path associated with this device. * * @return */ public String getUsbDevicePath() { return (String) getProperty(USB_EVENT_DEVICE_PATH_PROPERTY); } /** * Returns the USB device type. * * @return UsbDeviceType or null if the property is not set * @since 1.4 */ public UsbDeviceType getUsbDeviceType() { return (UsbDeviceType) getProperty(USB_EVENT_DEVICE_TYPE_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType @SuppressWarnings("checkstyle:interfaceIsType") public interface UsbDeviceEvent { /** Name of the property to access the USB port of this device **/ public static final String USB_EVENT_USB_PORT_PROPERTY = "usb.port"; /** * Name of the property to access the resource name associated with this USB device (e.g. /dev/ttyUSB3, eth3, etc * depending on the device type) */ public static final String USB_EVENT_RESOURCE_PROPERTY = "usb.resource"; /** Name of the property to access the vendor id **/ public static final String USB_EVENT_VENDOR_ID_PROPERTY = "usb.vendor.id"; /** Name of the property to access the product id **/ public static final String USB_EVENT_PRODUCT_ID_PROPERTY = "usb.product.id"; /** Name of the property to access the manufacturer name **/ public static final String USB_EVENT_MANUFACTURER_NAME_PROPERTY = "usb.manufacturer.name"; /** Name of the property to access the product name **/ public static final String USB_EVENT_PRODUCT_NAME_PROPERTY = "usb.product.name"; /** Name of the property to access the USB bus number **/ public static final String USB_EVENT_BUS_NUMBER_PROPERTY = "usb.bus.number"; /** Name of the property to access the USB device path **/ public static final String USB_EVENT_DEVICE_PATH_PROPERTY = "usb.device.path"; /** * Name of the property to access the USB device type * * @since 1.4 **/ public static final String USB_EVENT_DEVICE_TYPE_PROPERTY = "usb.device.type"; /** * Name of the property to access the interface number of a USB device * * @since 1.4 **/ public static final String USB_EVENT_USB_INTERFACE_NUMBER = "usb.interface.number"; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceRemovedEvent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import java.util.Map; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.event.Event; /** * An event raised when a USB device has been removed from the system. * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbDeviceRemovedEvent extends Event implements UsbDeviceEvent { /** Topic of the UsbDeviceRemovedEvent */ public static final String USB_EVENT_DEVICE_REMOVED_TOPIC = "org/eclipse/kura/usb/NetworkEvent/device/REMOVED"; public UsbDeviceRemovedEvent(Map properties) { super(USB_EVENT_DEVICE_REMOVED_TOPIC, properties); } /** * Returns the name of the USB port. * * @return */ public String getUsbPort() { return (String) getProperty(USB_EVENT_USB_PORT_PROPERTY); } /** * Returns the name of the USB resource associated with this device. * * @return */ public String getUsbResource() { return (String) getProperty(USB_EVENT_RESOURCE_PROPERTY); } /** * Returns the name of the USB vendor ID associated with this device. * * @return */ public String getUsbVendorId() { return (String) getProperty(USB_EVENT_VENDOR_ID_PROPERTY); } /** * Returns the name of the USB product ID associated with this device. * * @return */ public String getUsbProductId() { return (String) getProperty(USB_EVENT_PRODUCT_ID_PROPERTY); } /** * Returns the name of the USB manufacturer name associated with this device. * * @return */ public String getUsbManufacturerName() { return (String) getProperty(USB_EVENT_MANUFACTURER_NAME_PROPERTY); } /** * Returns the name of the USB product name associated with this device. * * @return */ public String getUsbProductName() { return (String) getProperty(USB_EVENT_PRODUCT_NAME_PROPERTY); } /** * Returns the name of the USB bus number associated with this device. * * @return */ public String getUsbBusNumber() { return (String) getProperty(USB_EVENT_BUS_NUMBER_PROPERTY); } /** * Returns the name of the USB device path associated with this device. * * @return */ public String getUsbDevicePath() { return (String) getProperty(USB_EVENT_DEVICE_PATH_PROPERTY); } /** * Returns the USB device type. * * @return UsbDeviceType or null if the property is not set * @since 1.4 */ public UsbDeviceType getUsbDeviceType() { return (UsbDeviceType) getProperty(USB_EVENT_DEVICE_TYPE_PROPERTY); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbDeviceType.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.usb; /** * UsbDeviceType represents the type of USB device. * Possible values are: * UsbBlockDevice, UsbModemDevice, UsbNetDevice and UsbTtyDevice * * @since 1.4 */ public enum UsbDeviceType { USB_BLOCK_DEVICE, USB_MODEM_DEVICE, USB_NET_DEVICE, USB_TTY_DEVICE } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbModemDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.kura.net.modem.ModemDevice; import org.osgi.annotation.versioning.ProviderType; /** * Representation of USB modem devices * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbModemDevice extends AbstractUsbDevice implements ModemDevice { /** The TTY devices associated with modem **/ private final ArrayList ttyDevs; /** The block devices associated with the modem **/ private final ArrayList blockDevs; public UsbModemDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath) { super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath); this.ttyDevs = new ArrayList<>(); this.blockDevs = new ArrayList<>(); } public UsbModemDevice(AbstractUsbDevice usbDevice) { super(usbDevice); this.ttyDevs = new ArrayList<>(); this.blockDevs = new ArrayList<>(); } @Override public List getSerialPorts() { List serialPorts = new ArrayList<>(); for (TtyDev dev : this.ttyDevs) { serialPorts.add(dev.getPortName()); } return serialPorts; } /** * Return a list of tty devices, sorted in a way to facilitate the client code identifying dedicated devices, * e.g. for AT commands, PPP link or NMEA sentences, based on their position in the list. * Originally, only the tty name was used for the comparison. This proved to be wrong as a tty name does reliably * identify the USB interface number (bInterfaceNumber) of the tty device. * To preserve the API contract, the tty devices can be added specifying the USB interface number and this will be * used to sort the list. * * @return sorted list of tty devices */ public List getTtyDevs() { return getSerialPorts(); } /** * @return sorted list of block devices */ public List getBlockDevs() { return Collections.unmodifiableList(this.blockDevs); } /** * Adds a tty device identified by its name and USB interface number (bInterfaceNumber). * The devices will be sorted by the interface number. If this is missing, the name will be used. * * @since 1.4 * * @param ttyDev * the name of the tty device * @param interfaceNumber * the number of the interface as described by the bInterfaceNumber property */ public void addTtyDev(String ttyDev, Integer interfaceNumber) { TtyDev dev = new TtyDev(ttyDev, interfaceNumber); if (!this.ttyDevs.contains(dev)) { this.ttyDevs.add(new TtyDev(ttyDev, interfaceNumber)); Collections.sort(this.ttyDevs, new TtyDevComparator()); } } /** * @deprecated this method is deprecated in favor of addTtyDev(String ttyDev, Integer interfaceNumber) */ @Deprecated public void addTtyDev(String ttyDev) { addTtyDev(ttyDev, null); } /** * Adds a block device identified by its name. The block devices will be sorted by the name. * * @param blockDev * the name of the block device */ public void addBlockDev(String blockDev) { if (!this.blockDevs.contains(blockDev)) { this.blockDevs.add(blockDev); Collections.sort(this.blockDevs, new DevNameComparator()); } } /** * Remove a tty device form the list. * * @param ttyDev * the name of the tty device * @return true if the list contained the specified device */ public boolean removeTtyDev(String ttyDev) { return this.ttyDevs.remove(new TtyDev(ttyDev)); } /** * Remove a block device form the list. * * @param blockDev * the name of the block device * @return true if the list contained the specified device */ public boolean removeBlockDev(String blockDev) { return this.blockDevs.remove(blockDev); } @Override public int hashCode() { final int prime = 37; int result = super.hashCode(); result = prime * result + (this.ttyDevs == null ? 0 : this.ttyDevs.hashCode()); result = prime * result + (this.blockDevs == null ? 0 : this.blockDevs.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } UsbModemDevice other = (UsbModemDevice) obj; if (this.ttyDevs == null) { if (other.ttyDevs != null) { return false; } } else if (!this.ttyDevs.equals(other.ttyDevs)) { return false; } if (this.blockDevs == null) { if (other.blockDevs != null) { return false; } } else if (!this.blockDevs.equals(other.blockDevs)) { return false; } return true; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("UsbModem ["); sb.append("vendorId=").append(getVendorId()); sb.append(", productId=").append(getProductId()); sb.append(", manufName=").append(getManufacturerName()); sb.append(", productName=").append(getProductName()); sb.append(", usbPort=").append(getUsbPort()); sb.append(", ttyDevs=").append(this.ttyDevs.toString()); sb.append(", blockDevs=").append(this.blockDevs.toString()); sb.append("]"); return sb.toString(); } private class DevNameComparator implements Comparator { @Override /** * Split the device name into the digit and non-digit portions and compare separately * i.e. for "/dev/ttyUSB9" and "/dev/ttyUSB10", the "/dev/ttyUSB" parts are first compared * then the "9" and "10" are compared numerically. */ public int compare(String dev1, String dev2) { int digitPos1 = getDigitPosition(dev1); int digitPos2 = getDigitPosition(dev2); String text1 = dev1.substring(0, digitPos1); String text2 = dev2.substring(0, digitPos2); String num1 = dev1.substring(digitPos1, dev1.length()); String num2 = dev2.substring(digitPos2, dev2.length()); // Compare text portion int textCompare = text1.compareTo(text2); if (textCompare != 0) { return textCompare; } // Compare numerical portion if (num1 == null || num1.isEmpty()) { if (num2 == null || num2.isEmpty()) { return 0; } else { return -1; } } else if (num2 == null || num2.isEmpty()) { return 1; } Integer int1 = Integer.parseInt(num1); Integer int2 = Integer.parseInt(num2); return int1.compareTo(int2); } private int getDigitPosition(String devName) { int pos = devName.length(); for (int i = devName.length() - 1; i >= 0; i--) { if (Character.isDigit(devName.charAt(i))) { pos = i; } else { break; } } return pos; } } private static class TtyDev { private final String portName; private Integer interfaceNumber; public TtyDev(String portName) { this.portName = portName; } public TtyDev(String portName, Integer interfaceNumber) { this.portName = portName; this.interfaceNumber = interfaceNumber; } public String getPortName() { return this.portName; } public Integer getInterfaceNumber() { return this.interfaceNumber; } @Override public String toString() { String number = this.interfaceNumber != null ? this.interfaceNumber.toString() : "null"; return "TtyDev [portName=" + this.portName + ", interfaceNumber=" + number + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.portName == null ? 0 : this.portName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } TtyDev other = (TtyDev) obj; if (this.portName == null) { if (other.portName != null) { return false; } } else if (!this.portName.equals(other.portName)) { return false; } return true; } } private class TtyDevComparator implements Comparator { @Override /** * If the devices have an interface number, use it for comparing. * Otherwise use the port names. * Note: this comparator imposes orderings that are inconsistent with equals. The comparison will be performed * on the interface numbers if present, while the equals method is based only on the port names. */ public int compare(TtyDev dev1, TtyDev dev2) { if (dev1.getInterfaceNumber() != null && dev2.getInterfaceNumber() != null) { return dev1.getInterfaceNumber().compareTo(dev2.getInterfaceNumber()); } else { return new DevNameComparator().compare(dev1.getPortName(), dev2.getPortName()); } } } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbNetDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * Representation of USB network devices * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbNetDevice extends AbstractUsbDevice { /** The interface name associated with this device **/ private final String interfaceName; public UsbNetDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath, String interfaceName) { super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath); this.interfaceName = interfaceName; } public String getInterfaceName() { return this.interfaceName; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (this.interfaceName == null ? 0 : this.interfaceName.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } UsbNetDevice other = (UsbNetDevice) obj; if (this.interfaceName == null) { if (other.interfaceName != null) { return false; } } else if (!this.interfaceName.equals(other.interfaceName)) { return false; } return true; } @Override public String toString() { return "UsbNetDevice [getInterfaceName()=" + getInterfaceName() + ", getVendorId()=" + getVendorId() + ", getProductId()=" + getProductId() + ", getManufacturerName()=" + getManufacturerName() + ", getProductName()=" + getProductName() + ", getUsbBusNumber()=" + getUsbBusNumber() + ", getUsbDevicePath()=" + getUsbDevicePath() + ", getUsbPort()=" + getUsbPort() + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import java.util.List; import javax.usb.UsbServices; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * OSGi interface for getting JSR-80 javax.usb.UsbServices currently available in the system. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface UsbService { /** * Gets the UsbServices currently available as specified by JSR-80 in the javax.usb * * @return The currently available javax.usb.UsbServices * @throws KuraException */ public UsbServices getUsbServices() throws KuraException; /** * Gets the USB devices on the gateway * * @return The currently attached USB devices */ public List getUsbDevices(); /** * Gets the USB block devices on the gateway * * @return The currently attached USB block devices */ public List getUsbBlockDevices(); /** * Gets the USB network devices on the gateway * * @return The currently attached USB network devices */ public List getUsbNetDevices(); /** * Gets the USB TTY devices on the gateway * * @return The currently attached USB TTY devices */ public List getUsbTtyDevices(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/UsbTtyDevice.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.usb; import org.osgi.annotation.versioning.ProviderType; /** * Representation of USB TTY devices * * @noextend This class is not intended to be subclassed by clients. */ @ProviderType public class UsbTtyDevice extends AbstractUsbDevice { /** The device node of the TTY device **/ private final String deviceNode; private final Integer interfaceNumber; public UsbTtyDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath, String deviceNode) { super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath); this.deviceNode = deviceNode; this.interfaceNumber = null; } /** * @since 1.4 */ @SuppressWarnings("checkstyle:parameterNumber") public UsbTtyDevice(String vendorId, String productId, String manufacturerName, String productName, String usbBusNumber, String usbDevicePath, String deviceNode, Integer interfaceNumber) { super(vendorId, productId, manufacturerName, productName, usbBusNumber, usbDevicePath); this.deviceNode = deviceNode; this.interfaceNumber = interfaceNumber; } /** * Returns the tty device node name * * @return the device node */ public String getDeviceNode() { return this.deviceNode; } /** * Returns the tty interface number * * @since 1.4 * * @return the interface number */ public Integer getInterfaceNumber() { return this.interfaceNumber; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + (this.deviceNode == null ? 0 : this.deviceNode.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } UsbTtyDevice other = (UsbTtyDevice) obj; if (this.deviceNode == null) { if (other.deviceNode != null) { return false; } } else if (!this.deviceNode.equals(other.deviceNode)) { return false; } return true; } @Override public String toString() { String number = getInterfaceNumber() != null ? getInterfaceNumber().toString() : "null"; return "UsbTtyDevice [getDeviceNode()=" + getDeviceNode() + ", getVendorId()=" + getVendorId() + ", getProductId()=" + getProductId() + ", getManufacturerName()=" + getManufacturerName() + ", getProductName()=" + getProductName() + ", getUsbBusNumber()=" + getUsbBusNumber() + ", getUsbDevicePath()=" + getUsbDevicePath() + ", getUsbPort()=" + getUsbPort() + ", getInterfaceNumber()=" + number + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/usb/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides services and interfaces for finding and managing USB devices within the system. * */ package org.eclipse.kura.usb; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/CriticalComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.watchdog; import org.osgi.annotation.versioning.ConsumerType; /** * CriticalComponent is an interface that can be used to denote a component of functionality that is * 'critical' to the nature of the system. If a component implements CriticalComponent then it must * state its name as well as its criticalComponentTimeout. The name is a unique identifier in the * system. The timeout is a length of time in milliseconds that the CriticalComponent must check in * with the {@link WatchdogService}. If the CriticalComponent goes for a time period of greater * than this timeout, based on the (@link WatchdogService } configuration it will perform some action * (such as rebooting the system). * */ @ConsumerType public interface CriticalComponent { /** * The unique identifier for this CriticalComponent * * @return a identifier unique to the {@link WatchdogService } */ public String getCriticalComponentName(); /** * The maximum amount of time in milliseconds that the CriticalComponent should check in * with the {@link WatchdogService} before the WatchdogService reboots the device. * * @return the timeout in milliseconds */ public int getCriticalComponentTimeout(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/WatchdogService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.watchdog; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides methods for starting, stopping, and updating a * hardware watchdog present on the system. Updating the watchdog, once * started, prevents the system from rebooting. * * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WatchdogService { /** * Starts the hardware watchdog on the device. If a timeout value has not been * set, the watchdog will use its default timeout.
* This call is no longer used. The life-cycle of the watchdog is controlled * by the configuration parameters of the WatchdogSerivce. The API call * is retained for compatibility reasons. */ @Deprecated public void startWatchdog(); /** * Stops the hardware Watchdog on the device * This call is no longer used. The life-cycle of the watchdog is controlled * by the configuration parameters of the WatchdogSerivce. The API call * is retained for compatibility reasons. */ @Deprecated public void stopWatchdog(); /** * Returns the timeout value for the hardware watchdog in increments of milliseconds. * * @return An int representing the hardware timeout value in milliseconds. */ public int getHardwareTimeout(); /** * Register a critical service with the Critical Service Check-in. * Once registered, the critical service must call the checkin() * method (at a frequency higher than 1/timeout) to prevent a system reboot. * * @param criticalComponent * The CriticalComponent to be registered. */ @Deprecated public void registerCriticalService(CriticalComponent criticalComponent); /** * Unregister a critical service with the Critical Service Check-in. * Once unregistered, the critical service will no longer call the * checkin() method. * * @param criticalComponent * The CriticalComponent to be unregistered. */ @Deprecated public void unregisterCriticalService(CriticalComponent criticalComponent); /** * Register a critical component with the WatchdogService Check-in. * Once registered, the critical component must call the checkin() * method (at a frequency higher than 1/timeout) to prevent a system reboot. * * @param criticalComponent * The CriticalComponent to be registered. */ public void registerCriticalComponent(CriticalComponent criticalComponent); /** * Unregister a critical component with the WatchdogService Check-in. * Once unregistered, the critical component will no longer call the * checkin() method. * * @param criticalComponent * The CriticalComponent to be unregistered. */ public void unregisterCriticalComponent(CriticalComponent criticalComponent); /** * Returns the list of the currently registered CriticalComponents * * @return A List of CriticalComponents */ public List getCriticalComponents(); /** * This method is used to notify the Watchdog Service that a critical service * has 'checked in' and the reboot timer should be reset. * * @param criticalComponent * The criticalComponent to be updated. */ public void checkin(CriticalComponent criticalComponent); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/watchdog/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * */ /** * Provides service for controlling hardware watchdog timer. * */ package org.eclipse.kura.watchdog; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireComponent.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import org.osgi.annotation.versioning.ProviderType; /** * WireComponent is a marker interface representing a generic identity for * {@link WireEmitter}s and {@link WireReceiver}s. A Wire Component is a * generalization of a component responsible for producing data also known as * {@code WireEmitter} and/or consuming data also known as {@code WireReceiver}. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface WireComponent { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import static java.util.Objects.requireNonNull; import org.eclipse.kura.annotation.NotThreadSafe; import org.eclipse.kura.annotation.Nullable; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.wireadmin.Wire; /** * The Class {@link WireConfiguration} represents a wiring configuration between a Wire * Emitter and a Wire Receiver. In a Wire Graph in Kura Wires, the connection that * connect two different Wire Components is known as {@link WireConfiguration}. *
*
* Two {@link WireConfiguration}s with equal {@code Emitter PID} and {@code Receiver PID} * are considered to be equal {@link WireConfiguration} instances and it is validated through * its {@link WireConfiguration#equals(Object)} and {@link WireConfiguration#hashCode()} * methods' contract and hence, it is suitable to be used with hash based collections. * * @see Wire * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @NotThreadSafe @ProviderType public class WireConfiguration { private final String emitterPid; @Nullable private String filter; private final String receiverPid; @Nullable private Wire wire; /** * Instantiates a new {@link WireConfiguration}. * * @param emitterPid * the Wire Emitter PID * @param receiverPid * the Wire Receiver PID * @throws NullPointerException * if any of the arguments is null */ public WireConfiguration(final String emitterPid, final String receiverPid) { requireNonNull(emitterPid, "Emitter PID cannot be null"); requireNonNull(receiverPid, "Receiver PID cannot be null"); this.emitterPid = emitterPid; this.receiverPid = receiverPid; } /** * Gets the Wire Emitter PID. * * @return the Wire Emitter PID */ public String getEmitterPid() { return this.emitterPid; } /** * Gets the associated filter. * * @return the filter */ public String getFilter() { return this.filter; } /** * Gets the Wire Receiver PID. * * @return the Wire Receiver PID */ public String getReceiverPid() { return this.receiverPid; } /** * Gets the associated {@link org.osgi.service.wireadmin.WireAdmin}' {@link Wire} instance. * * @return the {@link Wire} instance */ public Wire getWire() { return this.wire; } /** * Sets the filter for this {@link WireConfiguration} * * @param filter * the new filter */ public void setFilter(final String filter) { this.filter = filter; } /** * Sets the {@link Wire} instance. * * @param wire * the new {@link Wire} instance */ public void setWire(final Wire wire) { this.wire = wire; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (this.getClass() != obj.getClass()) { return false; } final WireConfiguration other = (WireConfiguration) obj; if (this.emitterPid == null) { if (other.emitterPid != null) { return false; } } else if (!this.emitterPid.equals(other.emitterPid)) { return false; } if (this.receiverPid == null) { if (other.receiverPid != null) { return false; } } else if (!this.receiverPid.equals(other.receiverPid)) { return false; } return true; } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.emitterPid == null ? 0 : this.emitterPid.hashCode()); result = prime * result + (this.receiverPid == null ? 0 : this.receiverPid.hashCode()); return result; } /** {@inheritDoc} */ @Override public String toString() { return "WireConfiguration [emitterPid=" + this.emitterPid + ", filter=" + this.filter + ", receiverPid=" + this.receiverPid + ", wire=" + this.wire + "]"; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireEmitter.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.service.wireadmin.Producer; /** * The WireEmitter is a marker interface which represents a wire component which * is a data producer that can produce values. The produced values can be used * by other {@link WireReceiver} components if it is wired with each other. * * @since 1.2 */ @ConsumerType public interface WireEmitter extends WireComponent, Producer { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireEnvelope.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import java.util.Collections; import java.util.List; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.wireadmin.BasicEnvelope; /** * The Class WireEnvelope represents a composite envelope to be used as an * abstract data to be transmitted between the wire emitter and the wire * receiver * * @see org.osgi.service.wireadmin.Envelope * @see BasicEnvelope * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class WireEnvelope extends BasicEnvelope { /** * The scope as agreed by the composite producer and consumer. This remains same * for all the Kura Wires communications. */ private static final String SCOPE = "WIRES"; /** * Instantiates a new WireEnvelope. * * @param emitterPid * the wire emitter PID * @param wireRecords * the {@link WireRecord}s */ public WireEnvelope(final String emitterPid, final List wireRecords) { super(Collections.unmodifiableList(wireRecords), emitterPid, SCOPE); } /** * Gets the wire emitter PID. * * @return the wire emitter PID */ public String getEmitterPid() { return (String) getIdentification(); } /** * Gets the {@link WireRecord}s. * * @return the {@link WireRecord}s */ @SuppressWarnings("unchecked") public List getRecords() { return (List) getValue(); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireHelperService.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import org.osgi.annotation.versioning.ProviderType; import org.osgi.framework.ServiceReference; /** * The interface WireHelperService is an service utility API to provide quick * and necessary operations for Kura Wires topology. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface WireHelperService { /** * Retrieves the Kura Service PID (kura.service.pid) of the wire component * * @param wireComponent * the wire component * @return the Service PID of the provided wire component or {@code null} if * the provided Wire Component PID is not associated with any * available Wire Component in the OSGi service registry * @throws NullPointerException * if the argument is null */ public String getPid(final WireComponent wireComponent); /** * Retrieves the OSGi Component Service PID (service.pid) of the provided * wire component PID * * @param wireComponentPid * the wire component PID (kura.service.pid) * @return the Service PID of the provided wire component or {@code null} if * the provided Wire Component PID is not associated with any * available Wire Component in the OSGi service registry * @throws NullPointerException * if the argument is null */ public String getServicePid(final String wireComponentPid); /** * Retrieves the OSGi Component Service PID (service.pid) of the wire * component * * @param wireComponent * the wire component * @return the Service PID of the provided wire component or {@code null} if * the provided Wire Component PID is not associated with any * available Wire Component in the OSGi service registry * @throws NullPointerException * if the argument is null */ public String getServicePid(final WireComponent wireComponent); /** * Checks whether the provided Wire Component PID belongs to a Wire Emitter * * @param wireComponentPid * the wire component PID (kura.service.pid) * @return true if the provided Wire Component PID belongs to a Wire Emitter * @throws NullPointerException * if the argument is null */ public boolean isEmitter(final String wireComponentPid); /** * Checks whether the provided Wire Component PID belongs to a Wire Receiver * * @param wireComponentPid * the wire component PID (kura.service.pid) * @return true if the provided Wire Component PID belongs to a Wire * Receiver * @throws NullPointerException * if the argument is null */ public boolean isReceiver(final String wireComponentPid); /** * Returns a Wire Support instance of the provided wire component * * @param wireComponent * the wire component * @param wireComponentRef * the {@link ServiceReference} that contains the metadata/configuration related to the wireComponent * @return the wire support instance * @throws NullPointerException * if the argument is null * @since 2.0 */ public WireSupport newWireSupport(WireComponent wireComponent, ServiceReference wireComponentRef); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireReceiver.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.service.wireadmin.Consumer; /** * The WireReceiver interface Represents a wire component which is a data * consumer that can receive produced or emitted values from upstream * {@link WireEmitter}. * * @since 1.2 */ @ConsumerType public interface WireReceiver extends WireComponent, Consumer { /** * Triggers when the wire component receives a {@link WireEnvelope} * * @param wireEnvelope * the received {@link WireEnvelope} * @throws NullPointerException * if the argument is null */ public void onWireReceive(WireEnvelope wireEnvelope); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireRecord.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import static java.util.Objects.requireNonNull; import java.util.Collections; import java.util.Map; import org.eclipse.kura.annotation.Immutable; import org.eclipse.kura.annotation.ThreadSafe; import org.eclipse.kura.type.TypedValue; import org.osgi.annotation.versioning.ProviderType; /** * The Class WireRecord represents a record to be transmitted during wire * communication between wire emitter and wire receiver * * @noextend This class is not intended to be extended by clients. * @since 1.2 */ @Immutable @ThreadSafe @ProviderType public class WireRecord { private final Map> properties; /** * Instantiates a new {@link WireRecord}. * * @param properties * Map that represents the key-value pairs * @throws NullPointerException * if any of the argument is null */ public WireRecord(final Map> properties) { requireNonNull(properties, "Properties cannot be null"); this.properties = Collections.unmodifiableMap(properties); } /** * Returns the properties stored in this {@link WireRecord} * * @return the fields */ public Map> getProperties() { return this.properties; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/WireSupport.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ package org.eclipse.kura.wire; import java.util.List; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.wireadmin.Consumer; import org.osgi.service.wireadmin.Producer; /** * The interface WireSupport is responsible for managing incoming as well as * outgoing wires of the contained Wire Component. This is also used to perform * wire related operations for instance, emit and receive {@link WireRecord}s. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.2 */ @ProviderType public interface WireSupport extends Producer, Consumer { /** * Emit the provided {@link WireRecord}s * * @param wireRecords * a List of {@link WireRecord} objects that will be sent to the receiver. * @throws NullPointerException * if the argument is null */ public void emit(List wireRecords); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/BarrierAggregatorFactory.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.graph; import org.osgi.annotation.versioning.ProviderType; /** * A marker interface for a factory that returns a {@link PortAggregator} that acts as a barrier for a provided set of * input ports. * The barrier behaves as follows: * *
    *
  • It maintains, for each port, a slot that can contain a WireEnvelope.
  • *
  • When a WireEnvelope is received on a port, the corresponding slot is filled with it. If the slot is not empty, * its content is replaced
  • *
  • When all slots are filled, their contents are provided to the registered callback.
  • *
  • The slots are cleared when the callback returns.
  • *
* * @since 1.4 */ @ProviderType public interface BarrierAggregatorFactory extends PortAggregatorFactory { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/CachingAggregatorFactory.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.graph; import org.osgi.annotation.versioning.ProviderType; /** * A marker interface for a factory that returns a {@link PortAggregator} that acts as a cache for a provided set of * input ports. * The cache behaves as follows: * *
    *
  • It maintains, for each port, a slot that can contain a WireEnvelope.
  • *
  • When a WireEnvelope is received on a port, the corresponding slot is filled with it. If the slot is not empty, * its content is replaced
  • *
  • When a WireEnvelope is received, the current contents of the slots are provided to the registered callback, even * if some of the slots are empty.
  • *
  • The slots are never cleared.
  • *
* * @since 1.4 */ @ProviderType public interface CachingAggregatorFactory extends PortAggregatorFactory { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/Constants.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; /** * Wire Graph related constants. * * @since 1.4 */ public enum Constants { WIRE_EMITTER_PORT_PROP_NAME("emitter.port"), WIRE_RECEIVER_PORT_PROP_NAME("receiver.port"), RECEIVER_PORT_COUNT_PROP_NAME("receiver.port.count"), EMITTER_PORT_COUNT_PROP_NAME("emitter.port.count"), RECEIVER_KURA_SERVICE_PID_PROP_NAME("receiver.kura.service.pid"), EMITTER_KURA_SERVICE_PID_PROP_NAME("emitter.kura.service.pid"); private final String value; private Constants(String v) { this.value = v; } public String value() { return this.value; } public static Constants fromValue(String v) { for (Constants c : Constants.values()) { if (c.value.equals(v)) { return c; } } throw new IllegalArgumentException(v); } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/EmitterPort.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import org.eclipse.kura.wire.WireEnvelope; import org.osgi.annotation.versioning.ProviderType; /** * This interface represents an emitter port * * @since 1.4 */ @ProviderType public interface EmitterPort extends Port { /** * This methods is invoked with the {@link WireEnvelope} that has to be sent to the other end of the wire. * * @param wireEnvelope * the message that needs to be sent. */ public void emit(WireEnvelope wireEnvelope); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/MultiportWireConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import org.eclipse.kura.wire.WireConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * This POJO is used to represent, in the Wires context, the configuration of a Wire used in a multi-port composer. * * @since 1.4 */ @ProviderType public class MultiportWireConfiguration extends WireConfiguration { private int emitterPort; private int receiverPort; public MultiportWireConfiguration(String emitterPid, String receiverPid, int emitterPort, int receiverPort) { super(emitterPid, receiverPid); this.emitterPort = emitterPort; this.receiverPort = receiverPort; } public int getEmitterPort() { return this.emitterPort; } public void setEmitterPort(int emitterPort) { this.emitterPort = emitterPort; } public int getReceiverPort() { return this.receiverPort; } public void setReceiverPort(int receiverPort) { this.receiverPort = receiverPort; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + this.emitterPort; result = prime * result + this.receiverPort; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (getClass() != obj.getClass()) { return false; } MultiportWireConfiguration other = (MultiportWireConfiguration) obj; if (this.emitterPort != other.emitterPort) { return false; } if (this.receiverPort != other.receiverPort) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/MultiportWireSupport.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.List; import org.eclipse.kura.wire.WireEnvelope; import org.eclipse.kura.wire.WireRecord; import org.eclipse.kura.wire.WireSupport; import org.osgi.annotation.versioning.ProviderType; /** * This interface extends {@link WireSupport} to provide multi-port support in Wires. * * @since 1.4 */ @ProviderType public interface MultiportWireSupport extends WireSupport { /** * Returns the list of EmitterPorts of a Wire Component * * @return a list of {@link EmitterPort} */ public List getEmitterPorts(); /** * Returns the list of ReceiverPorts associated to a Wire Component * * @return a list of {@link ReceiverPort} */ public List getReceiverPorts(); /** * This method allows to create a {@link WireEnvelope} from the list of {@link WireRecord} passed as an argument. * * @param records * a list of {@link WireRecord}s that will be wrapped into a {@link WireEnvelope} * @return a {@link WireEnvelope} that wraps the list of {@link WireRecord}s passed. */ public WireEnvelope createWireEnvelope(List records); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/Port.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.List; import org.osgi.annotation.versioning.ProviderType; import org.osgi.service.wireadmin.Wire; /** * This interface represents the port(s) associated to a Wire Component. * * @since 1.4 */ @ProviderType public interface Port { /** * This method returns the list of {@link Wire}s connected to this {@link Port} * * @return the list of {@link Wire} connected to this {@link Port} */ public List listConnectedWires(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/PortAggregator.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.List; import java.util.function.Consumer; import org.eclipse.kura.wire.WireEnvelope; import org.osgi.annotation.versioning.ProviderType; /** * Allows to implement an aggregation strategy for a given set of ports. See {@link BarrierAggregatorFactory} and * {@link CachingAggregatorFactory} for examples of possible strategies. * * @since 1.4 */ @ProviderType public interface PortAggregator { public void onWireReceive(Consumer> envelopes); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/PortAggregatorFactory.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * * Defines a factory service API that can be used to instantiate a specific {@link PortAggregator} strategy. * * @since 1.4 */ @ProviderType public interface PortAggregatorFactory { public PortAggregator build(List ports); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/ReceiverPort.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.function.Consumer; import org.eclipse.kura.wire.WireEnvelope; import org.osgi.annotation.versioning.ProviderType; /** * This interface marks the ports that are receiver ports of the associated Wire Component. * * @since 1.4 */ @ProviderType public interface ReceiverPort extends Port { public void onWireReceive(Consumer consumer); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.Collections; import java.util.Map; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * The Class represents the single Wire Graph Component configuration. It * contains the component configuration description and additional properties * that can be used for the component displaying in the composer.
*
* * @see ComponentConfiguration * * @noextend This class is not intended to be extended by clients. * @since 1.4 */ @ProviderType public class WireComponentConfiguration { private final ComponentConfiguration configuration; private final Map properties; public WireComponentConfiguration(ComponentConfiguration configuration, Map properties) { this.configuration = configuration; this.properties = Collections.unmodifiableMap(properties); } public ComponentConfiguration getConfiguration() { return this.configuration; } public Map getProperties() { return this.properties; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentDefinition.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.Map; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.annotation.versioning.ProviderType; /** * @noextend This class is not intended to be extended by clients. * @since 1.4 */ @ProviderType public class WireComponentDefinition { private String factoryPid; private int minInputPorts; private int maxInputPorts; private int defaultInputPorts; private int minOutputPorts; private int maxOutputPorts; private int defaultOutputPorts; private Map inputPortNames; private Map outputPortNames; private ComponentConfiguration componentOCD; public String getFactoryPid() { return this.factoryPid; } public void setFactoryPid(String factoryPid) { this.factoryPid = factoryPid; } public int getMinInputPorts() { return this.minInputPorts; } public void setMinInputPorts(int minInputPorts) { this.minInputPorts = minInputPorts; } public int getMaxInputPorts() { return this.maxInputPorts; } public void setMaxInputPorts(int maxInputPorts) { this.maxInputPorts = maxInputPorts; } public int getDefaultInputPorts() { return this.defaultInputPorts; } public void setDefaultInputPorts(int defaultInputPorts) { this.defaultInputPorts = defaultInputPorts; } public int getMinOutputPorts() { return this.minOutputPorts; } public void setMinOutputPorts(int minOutputPorts) { this.minOutputPorts = minOutputPorts; } public int getMaxOutputPorts() { return this.maxOutputPorts; } public void setMaxOutputPorts(int maxOutputPorts) { this.maxOutputPorts = maxOutputPorts; } public int getDefaultOutputPorts() { return this.defaultOutputPorts; } public void setDefaultOutputPorts(int defaultOutputPorts) { this.defaultOutputPorts = defaultOutputPorts; } public Map getInputPortNames() { return this.inputPortNames; } public void setInputPortNames(Map inputPortNames) { this.inputPortNames = inputPortNames; } public Map getOutputPortNames() { return this.outputPortNames; } public void setOutputPortNames(Map outputPortNames) { this.outputPortNames = outputPortNames; } public ComponentConfiguration getComponentOCD() { return this.componentOCD; } public void setComponentOCD(ComponentConfiguration componentOCD) { this.componentOCD = componentOCD; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireComponentDefinitionService.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.List; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This WireComponentDefinitionService allows to fetch the {@link WireComponentDefinition}s of the registered Wire * Components. * * @since 1.4 */ @ProviderType public interface WireComponentDefinitionService { /** * This method allows to list the {@link WireComponentDefinition}s for the registered Wire Components. * * @return a list of registered {@link WireComponentDefinition}s * @throws KuraException * if the get operation fails. */ public List getComponentDefinitions() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireGraphConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import java.util.Collections; import java.util.List; import org.osgi.annotation.versioning.ProviderType; /** * The Class represents the entire Wire Graph. It contains both the list of * components and the list of arcs that represent the current Wire Graph.
*
* * @see WireComponentConfiguration * @see org.eclipse.kura.wire.WireConfiguration * * @noextend This class is not intended to be extended by clients. * @since 1.4 */ @ProviderType public class WireGraphConfiguration { private final List wireComponentConfigurations; private final List wireConfigurations; public WireGraphConfiguration(List wireComponentConfigurations, List wireConfigurations) { this.wireComponentConfigurations = Collections.unmodifiableList(wireComponentConfigurations); this.wireConfigurations = Collections.unmodifiableList(wireConfigurations); } public List getWireComponentConfigurations() { return this.wireComponentConfigurations; } public List getWireConfigurations() { return this.wireConfigurations; } } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/WireGraphService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.graph; import org.eclipse.kura.KuraException; import org.osgi.annotation.versioning.ProviderType; /** * This interface provides all the needed methods to interact with the * WireGraph. * * @noimplement This interface is not intended to be implemented by clients. * @since 1.4 */ @ProviderType public interface WireGraphService { /** * This method allows to create and update the graph, by providing a * {@link WireGraphConfiguration}. * * @param graphConfiguration * A {@link WireGraphConfiguration} object that represents an updated * status of the Wire Graph * @throws {@link * KuraException} if the update operation fails */ public void update(WireGraphConfiguration graphConfiguration) throws KuraException; /** * This method allows to delete the current Wire Graph. * * @throws {@link * KuraException} if the delete operation fails */ public void delete() throws KuraException; /** * This method returns the current Wire Graph configuration. * * @return a {@link WireGraphConfiguration} object that represents the current * configuration of the Wire Graph * @throws {@link * KuraException} if the get operation fails */ public WireGraphConfiguration get() throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/graph/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ /** * Provides all the necessary APIs and classes to manipulate Kura Wires Graph * * @since 1.4 */ package org.eclipse.kura.wire.graph; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/MultiportWireEmitter.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.multiport; import org.eclipse.kura.wire.WireComponent; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.service.wireadmin.Producer; /** * The MultiportWireEmitter is a marker interface which represents a wire component which * is a data producer that can produce values. The produced values can be used * by other {@link org.eclipse.kura.wire.WireReceiver} components if it is wired with each other. * * @since 1.4 */ @ConsumerType public interface MultiportWireEmitter extends Producer, WireComponent { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/MultiportWireReceiver.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.wire.multiport; import org.eclipse.kura.wire.WireComponent; import org.osgi.annotation.versioning.ConsumerType; import org.osgi.service.wireadmin.Consumer; /** * The MultiportWireReceiver interface Represents a wire component which is a data * consumer that can receive produced or emitted values from upstream * {@link org.eclipse.kura.wire.WireEmitter}. * * @since 1.4 */ @ConsumerType public interface MultiportWireReceiver extends Consumer, WireComponent { } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/multiport/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ /** * Provides all the necessary APIs and classes to manipulate Kura Multiport Wire Components * * @since 1.4 */ package org.eclipse.kura.wire.multiport; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal ******************************************************************************/ /** * Provides all necessary APIs and all utility classes comprising necessary * static factory methods to manipulate Kura Wires topology * * @since 1.0.10 */ package org.eclipse.kura.wire; ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/QueryableWireRecordStoreProvider.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.store.provider; import java.util.List; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.wire.WireRecord; import org.osgi.annotation.versioning.ProviderType; /** * Represents a store that is capable to perform queries defined in an * implementation specific language and return the result in terms of a list of * {@link WireRecord}s. * * @since 2.5 * @noextend This class is not intended to be extended by clients. */ @ProviderType public interface QueryableWireRecordStoreProvider { /** * Perform the given query specified in an implementation defined language. * * @param query * the query to be run * @return a List of WireRecords that contains the result of the query * @throws KuraStoreException */ public List performQuery(String query) throws KuraStoreException; } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/WireRecordStore.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.store.provider; import java.util.List; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.wire.WireRecord; import org.osgi.annotation.versioning.ProviderType; /** * Represents a store that is capable to perform queries defined in an * implementation specific language and return the result in terms of a list of * {@link WireRecord}s. * * @since 2.5 * @noimplement This interface is not intended to be implemented by clients. */ @ProviderType public interface WireRecordStore { /** * Removes all records in the store except the most recent * noOfRecordsToKeep. * * @param noOfRecordsToKeep * the no of records to keep in the table * @throws KuraStoreException */ public void truncate(int noOfRecordsToKeep) throws KuraStoreException; /** * Returns the number of records currently in the store. * * @return the no of records currently in the store * @throws KuraStoreException */ public int getSize() throws KuraStoreException; /** * Insert the provided list of {@link WireRecord} instances in the store. * * @param records * the list of records to be inserted * @throws KuraStoreException */ public void insertRecords(List records) throws KuraStoreException; /** * * Closes the store, releasing any runtime resource allocated for it. */ public void close(); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/WireRecordStoreProvider.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.wire.store.provider; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.connection.listener.ConnectionListener; import org.osgi.annotation.versioning.ProviderType; /** * Represents a service that allows to create {@link WireRecordStore} instances. * * @since 2.5 * @noextend This class is not intended to be extended by clients. */ @ProviderType public interface WireRecordStoreProvider { /** * Opens or creates a {@link WireRecordStore} instance with the given name. Invoking * this method could allocate the resources required to support the returned {@link WireRecordStore} instance (for * example tables in a RDBMS).* * * @param name * the store name * @return the result {@link WireRecordStore}. * @throws KuraStoreException */ public WireRecordStore openWireRecordStore(String name) throws KuraStoreException; /** * Adds a {@link ConnectionListener}. A typical behavior of a client of this listener is to close the currently * open * {@link WireRecordStore} instances when a {@link ConnectionListener#disconnected()} event is received. * * @param listener * to add * * @since 2.5.0 */ public void addListener(ConnectionListener listener); /** * Removes a {@link ConnectionListener} * * @param listener * to remove * * @since 2.5.0 */ public void removeListener(ConnectionListener listener); } ================================================ FILE: kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/wire/store/provider/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ /** * Provides APIs to implement a Wire Record store. * * @since 2.5 */ package org.eclipse.kura.wire.store.provider; ================================================ FILE: kura/org.eclipse.kura.api/src/main/resources/org/eclipse/kura/core/messages/KuraExceptionMessagesBundle.properties ================================================ # # Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Red Hat Inc # CONFIGURATION_ERROR=Configuration Error: {0} INTERNAL_ERROR=An internal error occurred. {0} PORT_IN_USE=The port is in use. {0} SECURITY_EXCEPTION=The current subject is not authorized to perform this operation. {0} CONFIGURATION_ATTRIBUTE_UNDEFINED=The configuration attribute {0} is undefined. CONFIGURATION_ATTRIBUTE_INVALID=The configuration attribute {0} cannot accept value {1}: {2}. CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING=The configuration attribute {0} is required and no value has been specified. CONFIGURATION_UPDATE=Error updating Configuration of ConfigurableComponent {0} CONFIGURATION_SNAPSHOT_NOT_FOUND=Configuration snapshot {0} was not found. CONFIGURATION_SNAPSHOT_LISTING=Error Listing Snapshots. CONFIGURATION_SNAPSHOT_LOADING=Error Loading Snapshot CONFIGURATION_SNAPSHOT_TAKING=Error Taking Snapshot. CONFIGURATION_ROLLBACK=Error rolling back to snapshot. PARTIAL_SUCCESS=The operation succeeded only partially. NOT_CONNECTED=Not connected. TIMED_OUT=Timeout occurred while waiting for the operation to complete. CONNECTION_FAILED="Connection failed. {0}" TOO_MANY_INFLIGHT_MESSAGES="Too many in-flight messages." STORE_ERROR="Error performing operation on store. {0}" ENCODE_ERROR="Error encoding {0}." DECODER_ERROR="Error decoding {0}." INVALID_METRIC_EXCEPTION=Metric {0} is invalid. INVALID_MESSAGE_EXCEPTION=Message or its encoding is invalid. UNAVAILABLE_DEVICE=Device {0} is unavailable. CLOSED_DEVICE=Device {0} is closed. GPIO_EXCEPTION=Error accessing GPIO resource. {0} OS_COMMAND_ERROR=Command ''{0}'' exited with code {1}. PROCESS_EXECUTION_ERROR=Unable to execute system process {0} SUBSCRIPTION_ERROR=Error processing subscription for {0} BLE_NOTIFICATION_ERROR=Error during BLE notification. BLE_CONNECTION_ERROR=Error during BLE connection. BLE_PAIR_ERROR=Error during BLE pairing. BLE_RESOURCE_NOT_FOUND=BLE resource not found. BLE_IO_ERROR=Error during BLE IO activity. BLE_COMMAND_ERROR=Error executing ''{0}'' command. BLE_DISCOVERY_ERROR=Error during discovery procedure. SERIAL_PORT_INVALID_CONFIGURATION=The serial port ha an invalid configuration. {0} SERIAL_PORT_NOT_EXISTING=The serial port does not exist. {0} OPERATION_NOT_SUPPORTED=Operation {0} not supported. INVALID_PARAMETER=Invalid parameter. {0} BLE_REMOVE_ERROR=Error during device remove. BAD_REQUEST=Bad request. {0} NOT_FOUND=Not found. SERVICE_UNAVAILABLE=Service unavailable. {0}. DISCONNECTION_FAILED=Disconnection failed. ================================================ FILE: kura/org.eclipse.kura.camel/.gitignore ================================================ /target /bin ================================================ FILE: kura/org.eclipse.kura.camel/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.camel Bundle-SymbolicName: org.eclipse.kura.camel;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Bundle-ActivationPolicy: lazy Import-Package: javax.script, org.apache.camel;version="[2.21.0,3.0.0)", org.apache.camel.builder;version="[2.21.0,3.0.0)", org.apache.camel.core.osgi;version="[2.21.0,3.0.0)", org.apache.camel.impl;version="[2.21.0,3.0.0)", org.apache.camel.model;version="[2.21.0,3.0.0)", org.apache.camel.spi;version="[2.21.0,3.0.0)", org.apache.camel.util.function;version="[2.21,3.0)", org.apache.commons.io.input;version="[2.4,3.0)";resolution:=optional, org.eclipse.kura;version="[1.3,2.0)", org.eclipse.kura.cloud;version="[1.1,1.2)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.message;version="[1.0,2.0)", org.eclipse.kura.type;version="[1.1,2.0)", org.eclipse.kura.util.base;version="[1.0,2.0)", org.eclipse.kura.util.osgi;version="[1.0,2.0)", org.eclipse.kura.wire;version="[2.0,3.0)", org.osgi.framework;version="1.5.0", org.osgi.service.wireadmin;version="[1.0,2.0)", org.osgi.util.tracker;version="1.5.0", org.slf4j;version="1.7.0" Export-Package: org.eclipse.kura.camel;version="1.1.0", org.eclipse.kura.camel.bean;version="1.1.0";uses:="org.eclipse.kura.message", org.eclipse.kura.camel.camelcloud;version="1.1.0";uses:="org.apache.camel,org.eclipse.kura.cloud", org.eclipse.kura.camel.cloud;version="1.1.0"; uses:="org.apache.camel, org.apache.camel.impl, org.apache.camel.spi, org.eclipse.kura.camel.internal.cloud, org.eclipse.kura.message, org.eclipse.kura.cloud", org.eclipse.kura.camel.component;version="1.1.0"; uses:="org.osgi.framework, org.apache.camel.builder, org.eclipse.kura.camel.runner, org.apache.camel, org.eclipse.kura.configuration", org.eclipse.kura.camel.router;version="1.1.0";uses:="org.osgi.framework,org.apache.camel,org.eclipse.kura.camel.component", org.eclipse.kura.camel.runner;version="1.1.0"; uses:="org.osgi.framework, org.apache.camel.builder, org.apache.camel, org.apache.camel.spi, javax.script, org.apache.camel.model", org.eclipse.kura.camel.type;version="1.1.0";uses:="org.eclipse.kura.message", org.eclipse.kura.camel.utils;version="1.1.0";uses:="org.apache.camel" Service-Component: OSGI-INF/*.xml ================================================ FILE: kura/org.eclipse.kura.camel/META-INF/services/org/apache/camel/TypeConverter ================================================ org.eclipse.kura.camel.type.TypeConverter ================================================ FILE: kura/org.eclipse.kura.camel/OSGI-INF/kuraCloudResolver.properties ================================================ component=kura-cloud ================================================ FILE: kura/org.eclipse.kura.camel/OSGI-INF/kuraCloudResolver.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.camel/build.properties ================================================ # # Copyright (c) 2016, 2020 Red Hat Inc and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Red Hat Inc # source.. = src/main/java/ output.. = target/classes bin.includes = .,\ META-INF/,\ about.html,\ OSGI-INF/ src.includes = about.html ================================================ FILE: kura/org.eclipse.kura.camel/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.camel 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.camel.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/bean/PayloadFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.bean; import java.util.Date; import org.eclipse.kura.message.KuraPayload; public class PayloadFactory { public KuraPayload create(final String key, final Object value) { final KuraPayload result = new KuraPayload(); result.setTimestamp(new Date()); result.addMetric(key, value); return result; } public KuraPayload create(final Date timestamp) { final KuraPayload result = new KuraPayload(); result.setTimestamp(timestamp); return result; } public KuraPayload append(final KuraPayload payload, final String key, final Object value) { payload.addMetric(key, value); return payload; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/CamelCloudService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.camelcloud; import org.eclipse.kura.cloud.CloudService; /** * An extension interface adding Camel specific functionality to the {@link CloudService} interface */ public interface CamelCloudService extends CloudService { void registerBaseEndpoint(String applicationId, String baseEndpoint); void release(String applicationId); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/DefaultCamelCloudService.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.camelcloud; import static org.apache.camel.ServiceStatus.Started; import java.util.LinkedList; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.apache.camel.CamelContext; import org.eclipse.kura.KuraException; import org.eclipse.kura.camel.internal.camelcloud.CamelCloudClient; import org.eclipse.kura.cloud.CloudClient; /** * A default implementation of the {@link CamelCloudService} */ public class DefaultCamelCloudService implements CamelCloudService { private final CamelContext camelContext; private final Map clients = new ConcurrentHashMap<>(); private final Map baseEndpoints = new ConcurrentHashMap<>(); public DefaultCamelCloudService(CamelContext camelContext) { this.camelContext = camelContext; } @Override public CloudClient newCloudClient(String applicationId) throws KuraException { String baseEndpoint = this.baseEndpoints.get(applicationId); if (baseEndpoint == null) { baseEndpoint = "vm:%s"; } final CloudClient cloudClient = new CamelCloudClient(this, this.camelContext, applicationId, baseEndpoint); this.clients.put(applicationId, cloudClient); return cloudClient; } @Override public String[] getCloudApplicationIdentifiers() { return this.clients.keySet().toArray(new String[0]); } @Override public boolean isConnected() { return this.camelContext.getStatus() == Started; } @Override public void registerBaseEndpoint(String applicationId, String baseEndpoint) { this.baseEndpoints.put(applicationId, baseEndpoint); } @Override public void release(String applicationId) { CloudClient client = this.clients.remove(applicationId); if (client != null) { client.release(); } } public void dispose() { final LinkedList errors = new LinkedList<>(); for (CloudClient client : this.clients.values()) { try { client.release(); } catch (Exception e) { errors.add(e); } } this.clients.clear(); if (!errors.isEmpty()) { final Exception first = errors.pollFirst(); errors.forEach(first::addSuppressed); throw new RuntimeException(first); } } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/KuraCloudClientConstants.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.camelcloud; /** * Kura cloud constants */ public final class KuraCloudClientConstants { public static final String TOPIC = "topic"; public static final String APPLICATION_ID = "applicationId"; public static final String CAMEL_KURA_CLOUD = "CamelKuraCloudService"; public static final String CAMEL_KURA_CLOUD_TOPIC = CAMEL_KURA_CLOUD + ".topic"; public static final String CAMEL_KURA_CLOUD_QOS = CAMEL_KURA_CLOUD + ".qos"; public static final String CAMEL_KURA_CLOUD_RETAIN = CAMEL_KURA_CLOUD + ".retain"; public static final String CAMEL_KURA_CLOUD_PRIORITY = CAMEL_KURA_CLOUD + ".priority"; public static final String CAMEL_KURA_CLOUD_CONTROL = CAMEL_KURA_CLOUD + ".control"; public static final String CAMEL_KURA_CLOUD_DEVICEID = CAMEL_KURA_CLOUD + ".deviceId"; public static final String CAMEL_KURA_CLOUD_MESSAGEID = CAMEL_KURA_CLOUD + ".messageId"; private KuraCloudClientConstants() { } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/camelcloud/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Support for implementing a {@link org.eclipse.kura.cloud.CloudService} based on Apache Camel */ package org.eclipse.kura.camel.camelcloud; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud; import static org.eclipse.kura.camel.internal.utils.KuraServiceFactory.retrieveService; import java.util.Map; import org.apache.camel.CamelContext; import org.apache.camel.Endpoint; import org.apache.camel.impl.DefaultComponent; import org.eclipse.kura.camel.internal.cloud.CloudClientCache; import org.eclipse.kura.camel.internal.cloud.CloudClientCacheImpl; import org.eclipse.kura.cloud.CloudService; /** * The Camel component for providing "kura-cloud" */ public class KuraCloudComponent extends DefaultComponent { public static final String DEFAULT_NAME = "kura-cloud"; private CloudService cloudService; private CloudClientCache cache; public KuraCloudComponent() { super(); } // Constructors public KuraCloudComponent(final CamelContext context) { super(context); } public KuraCloudComponent(final CamelContext context, final CloudService cloudService) { super(context); this.cloudService = cloudService; } @Override protected void doStart() throws Exception { final CloudService cloudServiceInstance = lookupCloudService(); if (cloudServiceInstance == null) { throw new IllegalStateException( "'cloudService' is not set and not found in Camel context service registry"); } this.cache = new CloudClientCacheImpl(cloudServiceInstance); super.doStart(); } @Override protected void doStop() throws Exception { super.doStop(); if (this.cache != null) { this.cache.close(); this.cache = null; } } // Operations @Override protected Endpoint createEndpoint(String uri, String remain, Map parameters) throws Exception { final KuraCloudEndpoint kuraCloudEndpoint = new KuraCloudEndpoint(uri, this, this.cache); final String[] res = remain.split("/", 2); if (res.length < 2) { throw new IllegalArgumentException("Wrong kura-cloud URI format. Should be: kura-cloud:app/topic"); } parameters.put(KuraCloudConstants.APPLICATION_ID, res[0]); parameters.put(KuraCloudConstants.TOPIC, res[1]); setProperties(kuraCloudEndpoint, parameters); return kuraCloudEndpoint; } protected CloudService lookupCloudService() { if (this.cloudService == null) { this.cloudService = retrieveService(CloudService.class, getCamelContext().getRegistry()); } return this.cloudService; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudComponentResolver.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc * Eurotech *******************************************************************************/ package org.eclipse.kura.camel.cloud; import org.apache.camel.CamelContext; import org.apache.camel.Component; import org.apache.camel.spi.ComponentResolver; import org.eclipse.kura.cloud.CloudService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A resolver for "kura-cloud" *

* This resolver will register to any instance of {@link CloudService} and * wrap it into a {@link KuraCloudComponent} instance. *

*

* If you need finer grained control, consider using the {@link org.eclipse.kura.camel.runner.CamelRunner} mechanism. *

*/ public class KuraCloudComponentResolver implements ComponentResolver { private static final Logger logger = LoggerFactory.getLogger(KuraCloudComponentResolver.class); private CloudService cloudService; public void setCloudService(final CloudService cloudService) { this.cloudService = cloudService; } @Override public Component resolveComponent(final String name, final CamelContext context) throws Exception { switch (name) { case KuraCloudComponent.DEFAULT_NAME: final KuraCloudComponent component = new KuraCloudComponent(context, this.cloudService); logger.debug("Created new cloud component: {}", component); return component; default: } return null; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudConstants.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud; /** * Kura cloud constants */ public final class KuraCloudConstants { public static final String TOPIC = "topic"; public static final String APPLICATION_ID = "applicationId"; public static final String CAMEL_KURA_CLOUD = "CamelKuraCloud"; public static final String CAMEL_KURA_CLOUD_TOPIC = CAMEL_KURA_CLOUD + ".topic"; public static final String CAMEL_KURA_CLOUD_QOS = CAMEL_KURA_CLOUD + ".qos"; public static final String CAMEL_KURA_CLOUD_RETAIN = CAMEL_KURA_CLOUD + ".retain"; public static final String CAMEL_KURA_CLOUD_PRIORITY = CAMEL_KURA_CLOUD + ".priority"; public static final String CAMEL_KURA_CLOUD_CONTROL = CAMEL_KURA_CLOUD + ".control"; public static final String CAMEL_KURA_CLOUD_DEVICEID = CAMEL_KURA_CLOUD + ".deviceId"; private KuraCloudConstants() { } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudConsumer.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud; import static org.apache.camel.builder.ExchangeBuilder.anExchange; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC; import org.apache.camel.Endpoint; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.impl.DefaultConsumer; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.cloud.CloudClientListener; import org.eclipse.kura.message.KuraPayload; /** * Consumer implementation for {@link KuraCloudComponent} */ public class KuraCloudConsumer extends DefaultConsumer implements CloudClientListener { private final CloudClient cloudClient; public KuraCloudConsumer(final Endpoint endpoint, final Processor processor, final CloudClient cloudClient) { super(endpoint, processor); this.cloudClient = cloudClient; } // Life-cycle @Override protected void doStart() throws Exception { super.doStart(); this.log.debug("Starting CloudClientListener."); this.cloudClient.addCloudClientListener(this); if (this.cloudClient.isConnected()) { performSubscribe(); } } @Override protected void doStop() throws Exception { try { this.cloudClient.unsubscribe(getEndpoint().getTopic()); } catch (final Exception e) { this.log.info("Failed to unsubscribe", e); } this.cloudClient.removeCloudClientListener(this); this.log.debug("Stopping CloudClientListener."); super.doStop(); } // CloudClientListener callbacks @Override public void onControlMessageArrived(final String deviceId, final String appTopic, final KuraPayload msg, final int qos, final boolean retain) { onInternalMessageArrived(deviceId, appTopic, msg, qos, retain, true); } @Override public void onMessageArrived(final String deviceId, final String appTopic, final KuraPayload msg, final int qos, final boolean retain) { onInternalMessageArrived(deviceId, appTopic, msg, qos, retain, false); } @Override public void onConnectionLost() { this.log.debug("Executing empty 'onConnectionLost' callback."); } @Override public void onConnectionEstablished() { this.log.debug("Executing 'onConnectionEstablished'."); performSubscribe(); } private void performSubscribe() { try { this.log.debug("Perform subscribe: {} / {}", this.cloudClient, getEndpoint().getTopic()); this.cloudClient.subscribe(getEndpoint().getTopic(), 0); } catch (final KuraException e) { this.log.warn("Failed to subscribe", e); } } @Override public void onMessageConfirmed(final int messageId, final String appTopic) { this.log.debug("Executing empty 'onMessageConfirmed' callback with message ID {} and application topic {}.", messageId, appTopic); } @Override public void onMessagePublished(final int messageId, final String appTopic) { this.log.debug("Executing empty 'onMessagePublished' callback with message ID {} and application topic {}.", messageId, appTopic); } // Helpers private void onInternalMessageArrived(final String deviceId, final String appTopic, final KuraPayload message, final int qos, final boolean retain, final boolean control) { this.log.debug("Received message with deviceId {}, application topic {}.", deviceId, appTopic); final Exchange exchange = anExchange(getEndpoint().getCamelContext()) // .withBody(message) // .withHeader(CAMEL_KURA_CLOUD_TOPIC, appTopic) // .withHeader(CAMEL_KURA_CLOUD_DEVICEID, deviceId) // .withHeader(CAMEL_KURA_CLOUD_QOS, qos) // .withHeader(CAMEL_KURA_CLOUD_CONTROL, control) // .withHeader(CAMEL_KURA_CLOUD_RETAIN, retain) // .build(); exchange.setFromEndpoint(getEndpoint()); try { getProcessor().process(exchange); } catch (final Exception e) { handleException("Error while processing an incoming message:", e); } } // Getters @Override public KuraCloudEndpoint getEndpoint() { return (KuraCloudEndpoint) super.getEndpoint(); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudEndpoint.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud; import org.apache.camel.Consumer; import org.apache.camel.Processor; import org.apache.camel.impl.DefaultEndpoint; import org.apache.camel.spi.UriEndpoint; import org.apache.camel.spi.UriParam; import org.eclipse.kura.camel.internal.cloud.CloudClientCache; import org.eclipse.kura.camel.internal.cloud.CloudClientCache.CloudClientHandle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Endpoint implementation for {@link KuraCloudComponent} */ @UriEndpoint(scheme = "kura-cloud", title = "Kura Cloud", label = "iot,kura,cloud", syntax = "kura-cloud:applicationId/appTopic") public class KuraCloudEndpoint extends DefaultEndpoint { private static final Logger logger = LoggerFactory.getLogger(KuraCloudEndpoint.class); @UriParam(defaultValue = "") private String applicationId = ""; @UriParam(defaultValue = "") private String topic = ""; @UriParam(defaultValue = "0") private int qos; @UriParam(defaultValue = "false") private boolean retain = false; @UriParam(defaultValue = "5") private int priority = 5; @UriParam(defaultValue = "false") private boolean control = false; @UriParam(defaultValue = "") private String deviceId; private CloudClientHandle cloudClientHandle; private final CloudClientCache cache; public KuraCloudEndpoint(String uri, KuraCloudComponent kuraCloudComponent, CloudClientCache cache) { super(uri, kuraCloudComponent); this.cache = cache; } @Override protected void doStart() throws Exception { synchronized (this) { this.cloudClientHandle = this.cache.getOrCreate(this.applicationId); logger.debug("CloudClient {} -> {}", this.applicationId, this.cloudClientHandle.getClient()); } super.doStart(); } @Override protected void doStop() throws Exception { super.doStop(); synchronized (this) { if (this.cloudClientHandle != null) { this.cloudClientHandle.close(); this.cloudClientHandle = null; } } } @Override public Consumer createConsumer(Processor processor) throws Exception { return new KuraCloudConsumer(this, processor, this.cloudClientHandle.getClient()); } @Override public KuraCloudProducer createProducer() throws Exception { return new KuraCloudProducer(this, this.cloudClientHandle.getClient()); } @Override public boolean isSingleton() { return true; } @Override public KuraCloudComponent getComponent() { return (KuraCloudComponent) super.getComponent(); } public String getTopic() { return this.topic; } public void setTopic(String topic) { this.topic = topic; } public int getQos() { return this.qos; } public void setQos(int qos) { this.qos = qos; } public boolean isRetain() { return this.retain; } public void setRetain(boolean retain) { this.retain = retain; } public int getPriority() { return this.priority; } public void setPriority(int priority) { this.priority = priority; } public boolean isControl() { return this.control; } public void setControl(boolean control) { this.control = control; } public String getApplicationId() { return this.applicationId; } public void setApplicationId(String applicationId) { this.applicationId = applicationId; } public String getDeviceId() { return this.deviceId; } public void setDeviceId(String deviceId) { this.deviceId = deviceId; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/KuraCloudProducer.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_TOPIC; import org.apache.camel.Exchange; import org.apache.camel.Message; import org.apache.camel.impl.DefaultProducer; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.message.KuraPayload; /** * Producer implementation for {@link KuraCloudComponent} */ public class KuraCloudProducer extends DefaultProducer { // Visible for testing CloudClient cloudClient; public KuraCloudProducer(KuraCloudEndpoint endpoint, CloudClient cloudClient) { super(endpoint); this.cloudClient = cloudClient; } @Override public void process(Exchange exchange) throws Exception { Message in = exchange.getIn(); String topic = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_TOPIC, String.class), getEndpoint().getTopic()); int qos = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_QOS, Integer.class), getEndpoint().getQos()); int priority = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_PRIORITY, Integer.class), getEndpoint().getPriority()); boolean retain = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_RETAIN, Boolean.class), getEndpoint().isRetain()); boolean control = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_CONTROL, Boolean.class), getEndpoint().isControl()); String deviceId = firstNotNull(in.getHeader(CAMEL_KURA_CLOUD_DEVICEID, String.class), getEndpoint().getDeviceId()); Object body = in.getBody(); if (body == null) { throw new RuntimeException("Cannot produce null payload."); } if (!(body instanceof KuraPayload)) { KuraPayload payload = new KuraPayload(); if (body instanceof byte[]) { payload.setBody((byte[]) body); } else { byte[] payloadBytes = in.getBody(byte[].class); if (payloadBytes != null) { payload.setBody(in.getBody(byte[].class)); } else { payload.setBody(in.getBody(String.class).getBytes()); } } body = payload; } if (control) { if (deviceId != null) { this.cloudClient.controlPublish(deviceId, topic, (KuraPayload) body, qos, retain, priority); } else { this.cloudClient.controlPublish(topic, (KuraPayload) body, qos, retain, priority); } } else { this.cloudClient.publish(topic, (KuraPayload) body, qos, retain, priority); } } // Getters @Override public KuraCloudEndpoint getEndpoint() { return (KuraCloudEndpoint) super.getEndpoint(); } // Helpers private static T firstNotNull(T first, T second) { return first != null ? first : second; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/cloud/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Functionality to support access to {@link org.eclipse.kura.cloud.CloudService} instances from Apache Camel */ package org.eclipse.kura.camel.cloud; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractCamelComponent.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.component; import java.util.Dictionary; import java.util.Hashtable; import java.util.Map; import org.apache.camel.CamelContext; import org.eclipse.kura.camel.runner.CamelRunner; import org.eclipse.kura.camel.runner.CamelRunner.Builder; import org.eclipse.kura.camel.runner.ContextFactory; import org.eclipse.kura.camel.runner.ContextLifecycleListener; import org.eclipse.kura.util.base.StringUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An abstract base Camel component for the use inside of Kura *

* This class intended to be subclasses and customized according to needs. *

*/ public abstract class AbstractCamelComponent { static final String PROP_DISABLE_JMX = "org.eclipse.kura.camel.component.disableJmx"; private static final Logger logger = LoggerFactory.getLogger(AbstractCamelComponent.class); protected CamelRunner runner; private ServiceRegistration registration; protected void start(final Map properties) throws Exception { logger.info("Starting camel router"); final String kuraServiceId = Configuration.asString(properties, "camel.context.id"); final String contextId; if (kuraServiceId == null) { // allow disabling by setting an empty string contextId = Configuration.asString(properties, "kura.service.pid"); } else { contextId = kuraServiceId; } // create and configure final Builder builder = new CamelRunner.Builder(getBundleContext()); builder.contextFactory(getContextFactory()); builder.disableJmx(Boolean.getBoolean(PROP_DISABLE_JMX)); builder.addBeforeStart(this::beforeStart); if (!StringUtil.isNullOrEmpty(kuraServiceId) || !StringUtil.isNullOrEmpty(contextId)) { builder.addLifecycleListener(new ContextLifecycleListener() { @Override public void started(final CamelContext camelContext) throws Exception { AbstractCamelComponent.this.started(camelContext, kuraServiceId, contextId); } @Override public void stopping(final CamelContext camelContext) throws Exception { AbstractCamelComponent.this.stopping(); } }); } customizeBuilder(builder, properties); this.runner = builder.build(); // start this.runner.start(); } protected void started(final CamelContext camelContext, final String kuraServicePid, final String contextId) { // ensure we are reported stopped stopping(); // now start final Dictionary properties = new Hashtable<>(); if (!StringUtil.isNullOrEmpty(kuraServicePid)) { properties.put("kura.service.pid", kuraServicePid); } if (!StringUtil.isNullOrEmpty(contextId)) { properties.put(Constants.SERVICE_PID, contextId); properties.put("camel.context.id", contextId); } // register this.registration = getBundleContext().registerService(CamelContext.class, camelContext, properties); logger.info("Registered camel context: {}", this.registration); } protected void stopping() { if (this.registration != null) { logger.info("Unregister camel context: {}", this.registration); this.registration.unregister(); this.registration = null; } } /** * Customize the builder before it creates the runner *
* The default implementation is empty * * @param builder * the builder * @param properties * the properties provided to the {@link #start(Map)} method */ protected void customizeBuilder(final Builder builder, final Map properties) { } protected void stop() throws Exception { logger.info("Stopping camel router"); // stopping if (this.runner != null) { this.runner.stop(); this.runner = null; } } /** * Get the Camel context * * @return the camel context or {@code null} if the context is not started */ public CamelContext getCamelContext() { final CamelRunner camelRunner = this.runner; return camelRunner != null ? camelRunner.getCamelContext() : null; } /** * Called before the context is started * * @param camelContext * the Camel context which is being prepared for starting */ protected void beforeStart(final CamelContext camelContext) { } protected ContextFactory getContextFactory() { return CamelRunner.createOsgiFactory(getBundleContext()); } protected BundleContext getBundleContext() { return FrameworkUtil.getBundle(AbstractCamelComponent.class).getBundleContext(); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractJavaCamelComponent.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.component; import static java.lang.Boolean.getBoolean; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; import org.eclipse.kura.camel.runner.CamelRunner; import org.eclipse.kura.camel.runner.CamelRunner.Builder; import org.eclipse.kura.camel.runner.ContextFactory; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An abstract base class for implementing a {@link ConfigurableComponent} using * the Java DSL *

* This class intended to be subclasses and customized according to needs. *

*

* Note: This class is intended to be used as OSGi Service * Component. The methods {@link #start()} and {@link #stop()} have to be configured * accordingly. *

*

* The lifecycle methods of this class declare annotations based on {@link org.osgi.service.component.annotations}. * However those annotations are only discovered during build time. They are declared in order * to provide proper support when annotation based tooling is used. Otherwise those methods must be * mapped manually in the DS declaration. *

*/ public abstract class AbstractJavaCamelComponent extends RouteBuilder implements ConfigurableComponent { private static final String PROP_DISABLE_JMX = AbstractCamelComponent.PROP_DISABLE_JMX; private static final Logger logger = LoggerFactory.getLogger(AbstractJavaCamelComponent.class); protected CamelRunner runner; protected void start() throws Exception { logger.info("Starting camel router"); // create and configure final Builder builder = new CamelRunner.Builder(); builder.contextFactory(getContextFactory()); builder.disableJmx(getBoolean(PROP_DISABLE_JMX)); builder.addBeforeStart(camelContext -> { beforeStart(camelContext); camelContext.addRoutes(AbstractJavaCamelComponent.this); }); this.runner = builder.build(); // start this.runner.start(); } protected void stop() throws Exception { logger.info("Stopping camel router"); // stopping if (this.runner != null) { this.runner.stop(); this.runner = null; } } /** * Called before the context is started * * @param camelContext * the Camel context which is being prepared for starting */ protected void beforeStart(final CamelContext camelContext) { } protected ContextFactory getContextFactory() { return CamelRunner.createOsgiFactory(getBundleContext()); } protected BundleContext getBundleContext() { return FrameworkUtil.getBundle(AbstractCamelComponent.class).getBundleContext(); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/AbstractXmlCamelComponent.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.component; import static org.eclipse.kura.camel.component.Configuration.asString; import java.util.Map; import java.util.Objects; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An abstract base class for implementing a {@link ConfigurableComponent} using * configured XML *

* This class intended to be subclasses and customized according to needs. *

*

* Note: This class is intended to be used as OSGi Service * Component. There the methods {@link #activate(BundleContext, Map)}, * {@link #modified(Map)} and {@link #deactivate(BundleContext)} need to be * configured accordingly. *

*

* The lifecycle methods of this class declare annotations based on {@link org.osgi.service.component.annotations}. * However those annotations are only discovered during build time. They are declared in order * to provide proper support when annotation based tooling is used. Otherwise those methods must be * mapped manually in the DS declaration. *

*/ public abstract class AbstractXmlCamelComponent extends AbstractCamelComponent implements ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(AbstractXmlCamelComponent.class); private final String xmlDataProperty; public AbstractXmlCamelComponent(final String xmlDataProperty) { Objects.requireNonNull(xmlDataProperty); this.xmlDataProperty = xmlDataProperty; } protected void activate(final BundleContext context, final Map properties) throws Exception { try { start(properties); // apply current routes applyRoutes(properties); } catch (Exception e) { logger.warn("Problem activating component", e); // we need to suppress exceptions during start // otherwise Kura cannot configure us anymore } } protected void deactivate(final BundleContext context) throws Exception { try { stop(); } catch (Exception e) { logger.warn("Problem deactivating component", e); throw e; } } protected void modified(final Map properties) throws Exception { logger.debug("Updating properties: {}", properties); try { if (isRestartNeeded(properties)) { logger.info("Need restart"); stop(); start(properties); } // apply current routes applyRoutes(properties); } catch (Exception e) { logger.warn("Problem updating component", e); throw e; } } private void applyRoutes(final Map properties) throws Exception { this.runner.setRoutes(asString(properties, this.xmlDataProperty)); } protected boolean isRestartNeeded(final Map properties) { return false; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/Configuration.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.component; import java.util.Map; /** * A few helper methods for consuming configuration from a properties map */ public final class Configuration { private Configuration() { } /** * Get a string value, defaulting to {@code null} * * @param properties * the properties to read from, may be {@code null} * @param key * the key to read, may be {@code null} * @return the string value or {@code null} */ public static String asString(final Map properties, final String key) { return asString(properties, key, null); } /** * Get a string value * * @param properties * the properties to read from, may be {@code null} * @param key * the key to read, may be {@code null} * @param defaultValue * the default value, may be {@code null} * @return the string value or the default value */ public static String asString(final Map properties, final String key, final String defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof String) { return (String) value; } return defaultValue; } /** * Get a string value, unless it is empty *

* If the properties map contains the string, but the string is empty by {@link String#isEmpty()}, then * also the default value will be returned. *

* * @param properties * the properties to read from, may be {@code null} * @param key * the key to read, may be {@code null} * @param defaultValue * the default value, may be {@code null} * @return the string value or the default value */ public static String asStringNotEmpty(final Map properties, final String key, final String defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (!(value instanceof String)) { return defaultValue; } String stringValue = (String) value; if (stringValue.isEmpty()) { return defaultValue; } return stringValue; } public static Integer asInteger(final Map properties, final String key) { return asInteger(properties, key, null); } public static Integer asInteger(final Map properties, final String key, final Integer defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).intValue(); } return defaultValue; } public static int asInt(final Map properties, final String key, final int defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).intValue(); } return defaultValue; } public static Long asLong(final Map properties, final String key) { return asLong(properties, key, null); } public static Long asLong(final Map properties, final String key, final Long defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).longValue(); } return defaultValue; } public static long asLong(final Map properties, final String key, final long defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).longValue(); } return defaultValue; } public static Double asDouble(final Map properties, final String key) { return asDouble(properties, key, null); } public static Double asDouble(final Map properties, final String key, final Double defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).doubleValue(); } return defaultValue; } public static double asDouble(final Map properties, final String key, final double defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Number) { return ((Number) value).doubleValue(); } return defaultValue; } /** * Get a boolean parameter from the configuration * * @param properties * the configuration * @param key * the key to fetch * @return the boolean value from the configuration, or {@code false} if the property set is {@code null}, the * property is not set or it is not boolean */ public static boolean asBoolean(Map properties, String key) { return asBoolean(properties, key, false); } public static Boolean asBoolean(Map properties, String key, Boolean defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Boolean) { return (Boolean) value; } return defaultValue; } public static boolean asBoolean(Map properties, String key, boolean defaultValue) { if (properties == null) { return defaultValue; } final Object value = properties.get(key); if (value instanceof Boolean) { return (Boolean) value; } return defaultValue; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/component/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Components for building Kura application based on Apache Camel™ *

* This package provides a few classes which are intended as based classes * helping to implement simple Camel based components. *

*/ package org.eclipse.kura.camel.component; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/camelcloud/CamelCloudClient.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.internal.camelcloud; import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.apache.camel.ServiceStatus.Started; import static org.eclipse.kura.KuraErrorCode.CONFIGURATION_ERROR; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_CONTROL; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_DEVICEID; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_MESSAGEID; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_PRIORITY; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_QOS; import static org.eclipse.kura.camel.camelcloud.KuraCloudClientConstants.CAMEL_KURA_CLOUD_RETAIN; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.function.IntSupplier; import org.apache.camel.CamelContext; import org.apache.camel.Exchange; import org.apache.camel.Processor; import org.apache.camel.ProducerTemplate; import org.apache.camel.StartupListener; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.impl.DefaultShutdownStrategy; import org.apache.camel.spi.ShutdownStrategy; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.camel.camelcloud.CamelCloudService; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.cloud.CloudClientListener; import org.eclipse.kura.message.KuraPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Kura {@link CloudClient} based in Apache Camel */ public class CamelCloudClient implements CloudClient { private static final Logger logger = LoggerFactory.getLogger(CamelCloudClient.class); private final CamelCloudService cloudService; private final CamelContext camelContext; private final ProducerTemplate producerTemplate; private final List cloudClientListeners = new CopyOnWriteArrayList<>(); private final String applicationId; private final String baseEndpoint; private final ExecutorService executorService; private final Random messageIdRandom = new Random(); private final IntSupplier messageIdGenerator = () -> Math.abs(this.messageIdRandom.nextInt()); public CamelCloudClient(CamelCloudService cloudService, CamelContext camelContext, String applicationId, String baseEndpoint) { this.cloudService = cloudService; this.camelContext = camelContext; this.producerTemplate = camelContext.createProducerTemplate(); this.applicationId = applicationId; this.baseEndpoint = baseEndpoint; this.executorService = camelContext.getExecutorServiceManager().newThreadPool(this, "CamelCloudClient/" + applicationId, 0, 1); } public CamelCloudClient(CamelCloudService cloudService, CamelContext camelContext, String applicationId) { this(cloudService, camelContext, applicationId, "vm:%s"); } // Cloud client API @Override public String getApplicationId() { return this.applicationId; } @Override public void release() { this.cloudService.release(this.applicationId); this.camelContext.getExecutorServiceManager().shutdown(this.executorService); } @Override public boolean isConnected() { return this.camelContext.getStatus() == Started; } @Override public int publish(String topic, KuraPayload kuraPayload, int qos, boolean retain) throws KuraException { return publish(topic, kuraPayload, qos, retain, 5); } @Override public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException { return doPublish(false, deviceId, appTopic, payload, qos, retain, 5); } @Override public int publish(String topic, KuraPayload kuraPayload, int qos, boolean retain, int priority) throws KuraException { return doPublish(false, null, topic, kuraPayload, qos, retain, priority); } @Override public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { return doPublish(false, deviceId, appTopic, payload, qos, retain, priority); } @Override public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { KuraPayload kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); return publish(topic, kuraPayload, qos, retain, priority); } @Override public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { KuraPayload kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); return publish(deviceId, appTopic, kuraPayload, qos, retain, priority); } @Override public int controlPublish(String topic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { return doPublish(true, null, topic, payload, qos, retain, priority); } @Override public int controlPublish(String deviceId, String topic, KuraPayload kuraPayload, int qos, boolean retain, int priority) throws KuraException { return doPublish(true, deviceId, topic, kuraPayload, qos, retain, priority); } @Override public int controlPublish(String deviceId, String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { KuraPayload kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); return doPublish(true, deviceId, topic, kuraPayload, qos, retain, priority); } @Override public void subscribe(String topic, int qos) throws KuraException { forkSubscribe(false, null, topic, qos); } @Override public void subscribe(String deviceId, String appTopic, int qos) throws KuraException { forkSubscribe(false, deviceId, appTopic, qos); } @Override public void controlSubscribe(String topic, int qos) throws KuraException { forkSubscribe(true, null, topic, qos); } @Override public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException { forkSubscribe(true, deviceId, appTopic, qos); } @Override public void unsubscribe(String topic) throws KuraException { doUnsubscribe(null, topic); } @Override public void unsubscribe(String deviceId, String appTopic) throws KuraException { doUnsubscribe(deviceId, appTopic); } @Override public void controlUnsubscribe(String topic) throws KuraException { doUnsubscribe(null, topic); } @Override public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException { doUnsubscribe(deviceId, appTopic); } @Override public void addCloudClientListener(CloudClientListener cloudClientListener) { this.cloudClientListeners.add(cloudClientListener); } @Override public void removeCloudClientListener(CloudClientListener cloudClientListener) { this.cloudClientListeners.remove(cloudClientListener); } @Override public List getUnpublishedMessageIds() throws KuraException { return Collections.emptyList(); } @Override public List getInFlightMessageIds() throws KuraException { return Collections.emptyList(); } @Override public List getDroppedInFlightMessageIds() throws KuraException { return Collections.emptyList(); } // Helpers private void doUnsubscribe(String deviceId, String topic) throws KuraException { final String internalQueue = buildTopicName(deviceId, topic); try { ShutdownStrategy strategy = this.camelContext.getShutdownStrategy(); if (strategy instanceof DefaultShutdownStrategy) { if (((DefaultShutdownStrategy) strategy).getCurrentShutdownTaskFuture() != null) { logger.info("Skipping cleanup of '{}' since the camel context is being shut down", internalQueue); // we are "in shutdown" and would deadlock return; } } // perform shutdown this.camelContext.stopRoute(internalQueue); this.camelContext.removeRoute(internalQueue); } catch (Exception e) { throw new KuraException(KuraErrorCode.SUBSCRIPTION_ERROR, e, internalQueue); } } private String buildTopicName(final String deviceId, final String topic) { requireNonNull(topic, "'topic' must not be null"); if (deviceId == null) { return String.format("%s:%s", this.applicationId, topic); } else { return String.format("%s:%s:%s", deviceId, this.applicationId, topic); } } private int doPublish(boolean isControl, String deviceId, String topic, KuraPayload kuraPayload, int qos, boolean retain, int priority) throws KuraException { final String target = target(buildTopicName(deviceId, topic)); final int kuraMessageId = this.messageIdGenerator.getAsInt(); final Map headers = new HashMap<>(); headers.put(CAMEL_KURA_CLOUD_CONTROL, isControl); headers.put(CAMEL_KURA_CLOUD_MESSAGEID, kuraMessageId); headers.put(CAMEL_KURA_CLOUD_DEVICEID, deviceId); headers.put(CAMEL_KURA_CLOUD_QOS, qos); headers.put(CAMEL_KURA_CLOUD_RETAIN, retain); headers.put(CAMEL_KURA_CLOUD_PRIORITY, priority); logger.trace("Publishing: {} -> {} / {}", target, kuraPayload, this.camelContext); this.producerTemplate.sendBodyAndHeaders(target, kuraPayload, headers); return kuraMessageId; } private void forkSubscribe(final boolean isControl, final String deviceId, final String topic, final int qos) throws KuraException { /* * This construct is needed due to CAMEL-10206 * * It does fork off the subscription process, which actually creates a * new camel route, into the background since we currently may be in the * process of starting the camel context. If that is the case then the * newly added route won't be started since the camel context is in the * "starting" mode. Events won't get processed. * * So we do fork off the subscription process after the camel context * has been started. The executor is needed since, according to the * camel javadoc on StartupListener, the camel context may still be in * "starting" mode when the "onCamelContextStarted" method is called. */ try { this.camelContext.addStartupListener(new StartupListener() { @Override public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception { CamelCloudClient.this.executorService.submit(new Callable() { @Override public Void call() throws Exception { doSubscribe(isControl, deviceId, topic, qos); return null; } }); } }); } catch (Exception e) { throw new KuraException(KuraErrorCode.SUBSCRIPTION_ERROR, e, buildTopicName(deviceId, topic)); } } private void doSubscribe(final boolean isControl, String deviceId, final String topic, final int qos) throws KuraException { logger.debug("About to subscribe to topic {}:{} with QOS {}.", deviceId, topic, qos); final String internalQueue = buildTopicName(deviceId, topic); logger.debug("\tInternal target: {} / {}", target(internalQueue), this.camelContext); try { this.camelContext.addRoutes(new RouteBuilder() { @Override public void configure() throws Exception { from(target(internalQueue)).routeId(internalQueue).process(new Processor() { @Override public void process(Exchange exchange) throws Exception { logger.debug("Processing: {}", exchange); for (CloudClientListener listener : CamelCloudClient.this.cloudClientListeners) { logger.debug("\t{}", listener); Object body = exchange.getIn().getBody(); KuraPayload payload; if (body instanceof KuraPayload) { payload = (KuraPayload) body; } else { payload = new KuraPayload(); payload.setBody(getContext().getTypeConverter().convertTo(byte[].class, body)); } String deviceId = exchange.getIn().getHeader(CAMEL_KURA_CLOUD_DEVICEID, String.class); int qos = exchange.getIn().getHeader(CAMEL_KURA_CLOUD_QOS, 0, int.class); listener.onMessageArrived(deviceId, "camel", payload, qos, true); } } }); } }); } catch (Exception e) { logger.warn("Error while adding subscription route. Rethrowing root cause."); throw new KuraException(CONFIGURATION_ERROR, e); } } private String target(String topic) { if (this.baseEndpoint.contains("%s")) { return format(this.baseEndpoint, topic); } return this.baseEndpoint + topic; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/cloud/CloudClientCache.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.internal.cloud; import org.eclipse.kura.cloud.CloudClient; public interface CloudClientCache { interface CloudClientHandle extends AutoCloseable { CloudClient getClient(); } CloudClientHandle getOrCreate(String applicationId); void close(); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/cloud/CloudClientCacheImpl.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.internal.cloud; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.cloud.CloudService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudClientCacheImpl implements CloudClientCache { private final class CloudClientHandleImplementation implements CloudClientHandle { private final String applicationId; private final CloudClient client; public CloudClientHandleImplementation(String applicationId, CloudClient client) { this.applicationId = applicationId; this.client = client; } @Override public void close() throws Exception { removeHandle(CloudClientHandleImplementation.this, this.applicationId, this.client); } @Override public CloudClient getClient() { return this.client; } } private static final Logger logger = LoggerFactory.getLogger(CloudClientCacheImpl.class); private final CloudService cloudService; private final Map> cache = new HashMap<>(); public CloudClientCacheImpl(CloudService cloudService) { this.cloudService = cloudService; } @Override public synchronized CloudClientHandle getOrCreate(final String applicationId) { try { Set set = this.cache.get(applicationId); if (set == null) { logger.debug("CloudClient for application ID {} not found. Creating new one.", applicationId); set = new HashSet<>(); this.cache.put(applicationId, set); } else { logger.debug("CloudClient for application ID {} ... cache hit.", applicationId); } boolean created = false; CloudClient client = null; try { if (set.isEmpty()) { logger.debug("Creating new cloud client for: {}", applicationId); created = true; client = this.cloudService.newCloudClient(applicationId); } else { client = set.iterator().next().getClient(); logger.debug("Re-using cloud client: {} -> {}", applicationId, client); } try { final CloudClientHandle handle = new CloudClientHandleImplementation(applicationId, client); set.add(handle); return handle; } finally { // mark as returned client = null; } } finally { if (created && client != null) { // clean up leaked resource client.release(); } } } catch (KuraException e) { throw new RuntimeException(e); } } private void removeHandle(CloudClientHandle handle, String applicationId, CloudClient client) { logger.debug("Remove handle: {}", handle); final Set set; synchronized (this) { set = this.cache.get(applicationId); if (set == null) { return; } set.remove(handle); // don't process result, we clean up anyway if (set.isEmpty()) { logger.debug("Removing last handle for: {}", applicationId); this.cache.remove(applicationId); } } if (set.isEmpty()) { // release outside of lock logger.debug("Releasing client: {} / {}", applicationId, client); client.release(); } } @Override public void close() { final List handles = new ArrayList<>(); synchronized (this) { for (final Set set : this.cache.values()) { handles.addAll(set); } this.cache.clear(); } // release outside the lock final Set clients = new HashSet<>(); for (final CloudClientHandle handle : handles) { final CloudClient client = handle.getClient(); if (clients.add(client)) { client.release(); logger.info("Closing client: {}", client); } } } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/internal/utils/KuraServiceFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.internal.utils; import static org.slf4j.LoggerFactory.getLogger; import java.util.Set; import org.apache.camel.spi.Registry; import org.slf4j.Logger; public final class KuraServiceFactory { // Logger private static final Logger logger = getLogger(KuraServiceFactory.class); // Constructors private KuraServiceFactory() { } // Operations public static T retrieveService(final Class clazz, final Registry registry) { if (registry == null) { throw new IllegalArgumentException("Registry cannot be null."); } Set servicesFromRegistry = registry.findByType(clazz); if (servicesFromRegistry.size() == 1) { T service = servicesFromRegistry.iterator().next(); logger.info("Found Kura " + clazz.getCanonicalName() + " in the registry. Kura component will use that instance."); return service; } else if (servicesFromRegistry.size() > 1) { throw new IllegalStateException("Too many " + clazz.getCanonicalName() + " services found in a registry: " + servicesFromRegistry.size()); } else { throw new IllegalArgumentException( "No " + clazz.getCanonicalName() + " service instance found in a registry."); } } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Basic Apache Camel™ functionality *

* For information on how to create a component based on Apache Camel see: *

*
    *
  • {@link org.eclipse.kura.camel.runner.CamelRunner}
  • *
  • {@link org.eclipse.kura.camel.component}
  • *
*/ package org.eclipse.kura.camel; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/router/CamelRouter.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc * Eurotech *******************************************************************************/ package org.eclipse.kura.camel.router; import java.util.Map; import java.util.Objects; import org.apache.camel.CamelContext; import org.eclipse.kura.camel.component.AbstractXmlCamelComponent; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; /** * The class provides a compatibility layer for the older API * * @deprecated Use the {@link org.eclipse.kura.camel.runner.CamelRunner}, one of the abstract implementations from * {@link org.eclipse.kura.camel.component} or the native * {@link org.apache.camel.core.osgi.OsgiDefaultCamelContext} */ @Deprecated public abstract class CamelRouter extends AbstractXmlCamelComponent implements BundleActivator { protected CamelContext camelContext; public CamelRouter() { super("camel.route.xml"); } @Override protected void activate(BundleContext context, Map properties) throws Exception { super.activate(context, properties); this.camelContext = getCamelContext(); } @Override protected void deactivate(BundleContext context) throws Exception { this.camelContext = null; super.deactivate(context); } protected T service(Class serviceType) { Objects.requireNonNull(serviceType); final ServiceReference reference = getBundleContext().getServiceReference(serviceType); return reference == null ? null : getBundleContext().getService(reference); } protected T requiredService(final Class serviceType) { Objects.requireNonNull(serviceType); final ServiceReference reference = getBundleContext().getServiceReference(serviceType); if (reference == null) { throw new IllegalStateException("Cannot find service: " + serviceType.getName()); } return getBundleContext().getService(reference); } protected String camelXmlRoutesPid() { return "kura.camel"; } protected String camelXmlRoutesProperty() { return "kura.camel." + FrameworkUtil.getBundle(this.getClass()).getSymbolicName() + ".route"; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/router/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Old Camel API of Kura * * @deprecated For alternatives see the deprecation note of {@link CamelRouter} */ package org.eclipse.kura.camel.router; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/AbstractRoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import static org.eclipse.kura.camel.runner.CamelRunner.removeMissingRoutes; import org.apache.camel.CamelContext; import org.apache.camel.model.RoutesDefinition; public abstract class AbstractRoutesProvider implements RoutesProvider { @Override public void applyRoutes(final CamelContext camelContext) throws Exception { final RoutesDefinition routes = getRoutes(camelContext); removeMissingRoutes(camelContext, routes.getRoutes()); camelContext.addRouteDefinitions(routes.getRoutes()); } protected abstract RoutesDefinition getRoutes(CamelContext camelContext) throws Exception; } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/BeforeStart.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; @FunctionalInterface public interface BeforeStart { public void beforeStart(CamelContext camelContext) throws Exception; } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/BuilderRoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; import org.apache.camel.builder.RouteBuilder; public class BuilderRoutesProvider implements RoutesProvider { private final RouteBuilder builder; public BuilderRoutesProvider(final RouteBuilder builder) throws Exception { this.builder = builder; } @Override public void applyRoutes(CamelContext camelContext) throws Exception { CamelRunner.removeMissingRoutes(camelContext, this.builder.getRouteCollection().getRoutes()); camelContext.addRoutes(this.builder); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/CamelRunner.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.camel.CamelContext; import org.apache.camel.Route; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.core.osgi.OsgiDefaultCamelContext; import org.apache.camel.core.osgi.OsgiServiceRegistry; import org.apache.camel.impl.CompositeRegistry; import org.apache.camel.impl.SimpleRegistry; import org.apache.camel.model.OptionalIdentifiedDefinition; import org.apache.camel.model.RouteDefinition; import org.apache.camel.model.RoutesDefinition; import org.apache.camel.spi.ComponentResolver; import org.apache.camel.spi.LanguageResolver; import org.apache.camel.spi.Registry; import org.apache.camel.util.function.ThrowingBiConsumer; import org.eclipse.kura.camel.cloud.KuraCloudComponent; import org.eclipse.kura.cloud.CloudService; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A lifecycle manager for running a CamelContext *

* Use the {@link Builder} class to create instances of the {@link CamelRunner}. *

*/ public class CamelRunner { private static final Logger logger = LoggerFactory.getLogger(CamelRunner.class); /** * Creates a new {@link ContextFactory} backed by {@link OsgiDefaultCamelContext} * * @param bundleContext * the bundle context to use * @return a context factory creating {@link OsgiDefaultCamelContext}s */ public static ContextFactory createOsgiFactory(final BundleContext bundleContext) { Objects.requireNonNull(bundleContext); return registry -> new OsgiDefaultCamelContext(bundleContext, registry); } /** * Creates a new {@link RegistryFactory} backed by {@link OsgiServiceRegistry} * * @param bundleContext * the bundle context to use * @return a registry factory creating {@link OsgiServiceRegistry}s */ public static RegistryFactory createOsgiRegistry(final BundleContext bundleContext) { Objects.requireNonNull(bundleContext); return () -> new OsgiServiceRegistry(bundleContext); } public static RegistryFactory createOsgiRegistry(final BundleContext bundleContext, final Map services) { Objects.requireNonNull(bundleContext); if (services == null || services.isEmpty()) { return createOsgiRegistry(bundleContext); } return () -> { final List registries = new LinkedList<>(); // add simple registry final SimpleRegistry simple = new SimpleRegistry(); simple.putAll(services); registries.add(simple); // add OSGi registry registries.add(new OsgiServiceRegistry(bundleContext)); // return composite return new CompositeRegistry(registries); }; } /** * A builder for creating {@link CamelRunner} instances */ public static final class Builder { private final BundleContext bundleContext; private RegistryFactory registryFactory; private ContextFactory contextFactory; private final List> dependencies; private final List beforeStarts; private final List lifecycleListeners; private boolean disableJmx = true; private int shutdownTimeout = 5; public Builder() { this(FrameworkUtil.getBundle(CamelRunner.class).getBundleContext()); } public Builder(final BundleContext bundleContext) { Objects.requireNonNull(bundleContext); this.bundleContext = bundleContext; this.registryFactory = createOsgiRegistry(bundleContext); this.contextFactory = createOsgiFactory(bundleContext); this.dependencies = new LinkedList<>(); this.beforeStarts = new LinkedList<>(); this.lifecycleListeners = new LinkedList<>(); } public Builder(final Builder other) { Objects.requireNonNull(other); this.bundleContext = other.bundleContext; this.registryFactory = other.registryFactory; this.contextFactory = other.contextFactory; this.dependencies = new LinkedList<>(other.dependencies); this.beforeStarts = new LinkedList<>(other.beforeStarts); this.lifecycleListeners = new LinkedList<>(other.lifecycleListeners); this.disableJmx = other.disableJmx; this.shutdownTimeout = other.shutdownTimeout; } /** * Disable the use of JMX in the CamelContext *

* JMX is disabled by default. *

* * @param disableJmx * whether JMX should be disabled or not * @return the builder instance */ public Builder disableJmx(final boolean disableJmx) { this.disableJmx = disableJmx; return this; } /** * The shutdown timeout *

* This defaults to 5 seconds *

* * @param shutdownTimeout * The shutdown timeout in seconds * @return the builder instance */ public Builder shutdownTimeout(final int shutdownTimeout) { this.shutdownTimeout = shutdownTimeout; return this; } public Builder osgiContext(final BundleContext bundleContext) { Objects.requireNonNull(bundleContext); return contextFactory(createOsgiFactory(bundleContext)); } public Builder registryFactory(final RegistryFactory registryFactory) { Objects.requireNonNull(registryFactory); this.registryFactory = registryFactory; return this; } public Builder contextFactory(final ContextFactory contextFactory) { Objects.requireNonNull(contextFactory); this.contextFactory = contextFactory; return this; } public Builder dependOn(final Filter filter, final ServiceConsumer consumer) { return dependOn(null, filter, consumer); } public Builder dependOn(BundleContext bundleContext, final Filter filter, final ServiceConsumer consumer) { Objects.requireNonNull(filter); Objects.requireNonNull(consumer); if (bundleContext == null) { bundleContext = Builder.this.bundleContext; } this.dependencies.add(new DefaultServiceDependency<>(bundleContext, filter, consumer)); return this; } /** * Depend on a specific {@link CloudService} instance *

* If a filter is specified then it will be combined with the filter for the object class of the * {@link CloudService}. * If the filter expression is omitted then only the object class filter will be used. *

* * @param bundleContext * the bundle context to use for service lookup * @param filter * the filter expression to use searching for the cloud service instance * @param consumer * the consumer processing the service instance * @return the builder instance */ public Builder cloudService(BundleContext bundleContext, final String filter, final ServiceConsumer consumer) { final String baseFilter = String.format("(%s=%s)", Constants.OBJECTCLASS, CloudService.class.getName()); try { if (filter != null && !filter.trim().isEmpty()) { // combined filter final Filter f = FrameworkUtil.createFilter(String.format("(&%s%s)", baseFilter, filter)); return dependOn(bundleContext, f, consumer); } else { // empty custom filter, so only filter for class name return dependOn(bundleContext, FrameworkUtil.createFilter(baseFilter), consumer); } } catch (InvalidSyntaxException e) { throw new RuntimeException("Failed to parse filter", e); } } /** * Depend on a specific {@link CloudService} instance *

* The cloud service will be injected into the camel context as component "kura-cloud". *

*

* If a filter is specified then it will be combined with the filter for the object class of the * {@link CloudService}. * If the filter expression is omitted then only the object class filter will be used. *

* * @param filter * optional filter expression * @return the builder instance */ public Builder cloudService(final String filter) { return cloudService((BundleContext) null, filter, addAsCloudComponent("kura-cloud")); } /** * Depend on a specific {@link CloudService} instance by key and value *

* This is a convenience method for {@link #cloudService(String)}. It will effectively call * this method with a filter of {@code "(" + attribute + "=" + value + ")"} *

* * @param attribute * the OSGi attribute to look for * @param value * the value the OSGi must have * @return the builder instance */ public Builder cloudService(final String attribute, final String value) { Objects.requireNonNull(attribute); Objects.requireNonNull(value); return cloudService(String.format("(%s=%s)", attribute, value)); } /** * Require a Camel component to be registered with OSGi before starting * * @param componentName * the component name (e.g. "timer") * @return the builder instance */ public Builder requireComponent(final String componentName) { try { final String filterString = String.format("(&(%s=%s)(%s=%s))", Constants.OBJECTCLASS, ComponentResolver.class.getName(), "component", componentName); final Filter filter = FrameworkUtil.createFilter(filterString); dependOn(filter, (context, service) -> { }); } catch (InvalidSyntaxException e) { throw new IllegalArgumentException(String.format("Illegal component name: '%s'", componentName), e); } return this; } /** * Require a Camel language to be registered with OSGi before starting * * @param languageName * the language name (e.g. "javaScript") * @return the builder instance */ public Builder requireLanguage(final String languageName) { try { final String filterString = String.format("(&(%s=%s)(%s=%s))", Constants.OBJECTCLASS, LanguageResolver.class.getName(), "language", languageName); final Filter filter = FrameworkUtil.createFilter(filterString); dependOn(filter, (context, service) -> { }); } catch (InvalidSyntaxException e) { throw new IllegalArgumentException(String.format("Illegal languageName name: '%s'", languageName), e); } return this; } public static ServiceConsumer addAsCloudComponent(final String componentName) { return (context, service) -> context.addComponent(componentName, new KuraCloudComponent(context, service)); } /** * Add an operation which will be executed before the Camel context is started * * @param beforeStart * the action to start * @return the builder instance */ public Builder addBeforeStart(final BeforeStart beforeStart) { Objects.requireNonNull(beforeStart); this.beforeStarts.add(beforeStart); return this; } /** * Add a context lifecylce listener. * * @param listener * The listener to add * @return the builder instance */ public Builder addLifecycleListener(final ContextLifecycleListener listener) { Objects.requireNonNull(listener); this.lifecycleListeners.add(listener); return this; } /** * Build the actual CamelRunner instance based on the current configuration of the builder instance *

* Modifications which will be made to the builder after the {@link #build()} method was called will * no affect the created CamelRunner instance. It is possible though to call the {@link #build()} method * multiple times. *

* * @return the new instance */ public CamelRunner build() { final List beforeStartsTemp = new ArrayList<>(this.beforeStarts); final List> dependenciesTemp = new ArrayList<>(this.dependencies); if (this.disableJmx) { beforeStartsTemp.add(CamelContext::disableJMX); } if (this.shutdownTimeout > 0) { final int shutdownTimeoutTemp = this.shutdownTimeout; beforeStartsTemp.add(camelContext -> { camelContext.getShutdownStrategy().setTimeUnit(TimeUnit.SECONDS); camelContext.getShutdownStrategy().setTimeout(shutdownTimeoutTemp); }); } return new CamelRunner(this.registryFactory, this.contextFactory, beforeStartsTemp, this.lifecycleListeners, dependenciesTemp); } } private final RegistryFactory registryFactory; private final ContextFactory contextFactory; private final List beforeStarts; private final List lifecycleListeners; private final List> dependencies; private CamelContext context; private RoutesProvider routes = EmptyRoutesProvider.INSTANCE; private DependencyRunner dependencyRunner; private CamelRunner(final RegistryFactory registryFactory, final ContextFactory contextFactory, final List beforeStarts, final List lifecycleListeners, final List> dependencies) { this.registryFactory = registryFactory; this.contextFactory = contextFactory; this.beforeStarts = beforeStarts; this.lifecycleListeners = lifecycleListeners; this.dependencies = dependencies; } private Registry createRegistry() { return this.registryFactory.createRegistry(); } private CamelContext createContext(final Registry registry) { return this.contextFactory.createContext(registry); } /** * Start the camel runner instance *

* This may not start the camel context right away if there are unresolved dependencies *

*/ public void start() { stop(); logger.info("Starting..."); this.dependencyRunner = new DependencyRunner<>(this.dependencies, new DependencyRunner.Listener() { @Override public void ready(final List> dependencies) { try { startCamel(dependencies); } catch (Exception e) { logger.warn("Failed to start context", e); } } @Override public void notReady() { try { stopCamel(); } catch (Exception e) { logger.warn("Failed to stop context", e); } } }); this.dependencyRunner.start(); } /** * Stop the camel runner instance */ public void stop() { if (this.dependencyRunner != null) { logger.info("Stopping..."); this.dependencyRunner.stop(); this.dependencyRunner = null; } } protected void startCamel(final List> dependencies) throws Exception { if (this.context != null) { logger.warn("Camel already running"); return; } final Registry registry = createRegistry(); final CamelContext camelContext = createContext(registry); beforeStart(camelContext); for (final ServiceDependency.Handle dep : dependencies) { dep.consume(camelContext); } this.context = camelContext; this.routes.applyRoutes(this.context); this.context.start(); fireLifecycle(this.context, ContextLifecycleListener::started); } protected void stopCamel() throws Exception { if (this.context != null) { fireLifecycle(this.context, ContextLifecycleListener::stopping); this.context.stop(); this.context = null; } } private void beforeStart(final CamelContext context) throws Exception { logger.debug("Running before starts..."); for (final BeforeStart beforeStart : this.beforeStarts) { beforeStart.beforeStart(context); } } private void fireLifecycle(final CamelContext context, final ThrowingBiConsumer consumer) { for (final ContextLifecycleListener listener : this.lifecycleListeners) { try { consumer.accept(listener, context); } catch (Exception e) { logger.warn("Failed to call listener", e); } } } /** * Remove a set of routes from the context *

* This is a helper method intended to be used by implementations of {@link RoutesProvider}. *

* * @param context * the context to work on * @param removedRouteIds * the ID to remove */ public static void removeRoutes(final CamelContext context, final Set removedRouteIds) { Objects.requireNonNull(context); Objects.requireNonNull(removedRouteIds); for (final String id : removedRouteIds) { try { logger.debug("Stopping route: {}", id); context.stopRoute(id); logger.debug("Removing route: {}", id); context.removeRoute(id); } catch (Exception e) { logger.warn("Failed to remove route: {}", id, e); } } } /** * Remove all routes from the context which are not in the new set *

* This is a helper method intended to be used by implementations of {@link RoutesProvider}. *

* * @param context * the context to work on * @param routes * the collection of new routes */ public static void removeMissingRoutes(final CamelContext context, final Collection routes) { Objects.requireNonNull(context); Objects.requireNonNull(routes); // gather new IDs final Set newRouteIds = fromDefs(routes); // eval removed final Set removedRouteIds = new HashSet<>(fromRoutes(context.getRoutes())); removedRouteIds.removeAll(newRouteIds); // remove from running context removeRoutes(context, removedRouteIds); } /** * Remove all routes of a context * * @param context * the context to work on */ public static void removeAllRoutes(final CamelContext context) { Objects.requireNonNull(context); // remove all routes removeRoutes(context, fromDefs(context.getRouteDefinitions())); } /** * Clear all routes from the context */ public void clearRoutes() { setRoutes(EmptyRoutesProvider.INSTANCE); } /** * Replace the current set of route with an new one * * @param routes * the new set of routes, may be {@code null} */ public void setRoutes(final RoutesProvider routes) { if (routes == null) { clearRoutes(); return; } this.routes = routes; final CamelContext camelContext = this.context; if (camelContext != null) { try { this.routes.applyRoutes(camelContext); } catch (final Exception e) { throw new RuntimeException(e); } } } /** * Replace the current set of route with an new one * * @param xml * the new set of routes, may be {@code null} */ public void setRoutes(final String xml) throws Exception { logger.info("Setting routes..."); if (xml == null || xml.trim().isEmpty()) { clearRoutes(); } else { setRoutes(new XmlRoutesProvider(xml)); } } /** * Replace the current set of route with an new one * * @param routes * the new set of routes, may be {@code null} */ public void setRoutes(final RoutesDefinition routes) throws Exception { logger.info("Setting routes..."); if (routes == null) { clearRoutes(); return; } setRoutes(new SimpleRoutesProvider(routes)); } /** * Replace the current set of route with an new one * * @param routeBuilder * the new set of routes, may be {@code null} */ public void setRoutes(final RouteBuilder routeBuilder) throws Exception { logger.info("Setting routes..."); if (routeBuilder == null) { clearRoutes(); return; } setRoutes(new BuilderRoutesProvider(routeBuilder)); } static Set fromRoutes(final Collection routes) { final Set result = new HashSet<>(routes.size()); for (final Route route : routes) { result.add(route.getId()); } return result; } private static > Set fromDefs(final Collection defs) { Objects.requireNonNull(defs); final Set result = new HashSet<>(defs.size()); for (final T def : defs) { final String id = def.getId(); if (id != null) { result.add(def.getId()); } } return result; } /** * Get the camel context *

* Note: This method may return {@code null} even after the {@link #start()} method was called * if there are unresolved dependencies for the runner. *

* * @return the camel context, if the camel context is currently not running then {@code null} is being returned */ public CamelContext getCamelContext() { return this.context; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ContextFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; import org.apache.camel.spi.Registry; public interface ContextFactory { public CamelContext createContext(Registry registry); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ContextLifecycleListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; public interface ContextLifecycleListener { public void started(CamelContext camelContext) throws Exception; public void stopping(CamelContext camelContext) throws Exception; } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/DefaultServiceDependency.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.util.Objects; import java.util.TreeMap; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class DefaultServiceDependency implements ServiceDependency { private final class HandleImpl implements Handle { private final BundleContext bundleContext; private final ServiceConsumer consumer; private final TreeMap, T> services = new TreeMap<>(); private final ServiceTracker tracker; private Runnable runnable; private final ServiceTrackerCustomizer customizer = new ServiceTrackerCustomizer() { @Override public T addingService(ServiceReference reference) { return adding(reference); } @Override public void modifiedService(ServiceReference reference, T service) { } @Override public void removedService(ServiceReference reference, T service) { removed(reference, service); } }; public HandleImpl(BundleContext bundleContext, Filter filter, Runnable runnable, final ServiceConsumer consumer) { this.bundleContext = bundleContext; this.consumer = consumer; this.runnable = runnable; this.tracker = new ServiceTracker<>(bundleContext, filter, HandleImpl.this.customizer); this.tracker.open(); } protected T adding(final ServiceReference reference) { final T service = this.bundleContext.getService(reference); this.services.put(reference, service); triggerUpdate(); return service; } protected void removed(final ServiceReference reference, final T service) { this.bundleContext.ungetService(reference); this.services.remove(reference); triggerUpdate(); } private void triggerUpdate() { final Runnable runnableTemp = this.runnable; if (runnableTemp != null) { runnableTemp.run(); } } @Override public void stop() { this.runnable = null; this.tracker.close(); } @Override public boolean isSatisfied() { return !this.services.isEmpty(); } @Override public void consume(C context) { this.consumer.consume(context, this.services.firstEntry().getValue()); } @Override public String toString() { return String.format("[Service - filter: %s]", DefaultServiceDependency.this.filter); } } private final BundleContext bundleContext; private final Filter filter; private final ServiceConsumer consumer; public DefaultServiceDependency(final BundleContext bundleContext, final Filter filter, final ServiceConsumer consumer) { Objects.requireNonNull(bundleContext); Objects.requireNonNull(filter); this.bundleContext = bundleContext; this.filter = filter; this.consumer = consumer; } @Override public Handle start(final Runnable runnable) { Objects.requireNonNull(runnable); return new HandleImpl(this.bundleContext, this.filter, runnable, this.consumer); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/DependencyRunner.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; import org.eclipse.kura.camel.runner.ServiceDependency.Handle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DependencyRunner { private static final Logger logger = LoggerFactory.getLogger(DependencyRunner.class); public interface Listener { public void ready(List> dependencies); public void notReady(); } private final ArrayList> dependencies; private final DependencyRunner.Listener listener; private List> dependencyHandles; private boolean lastState = false; private final Runnable update = new Runnable() { @Override public void run() { DependencyRunner.this.update(); } }; private boolean working; public DependencyRunner(final List> dependencies, final DependencyRunner.Listener listener) { Objects.requireNonNull(dependencies); Objects.requireNonNull(listener); this.dependencies = new ArrayList<>(dependencies); this.listener = listener; } public void start() { this.working = true; try { this.dependencyHandles = new LinkedList<>(); for (final ServiceDependency dep : this.dependencies) { this.dependencyHandles.add(dep.start(this.update)); } } finally { this.working = false; } // trigger first time if (isReady()) { triggerUpdate(true); } } public void stop() { this.working = true; try { for (final Handle dep : this.dependencyHandles) { dep.stop(); } } finally { this.working = false; } triggerUpdate(false); } private void update() { logger.debug("update"); if (this.working) { logger.debug("update - start/stop in progress"); return; } boolean state = isReady(); triggerUpdate(state); } private void triggerUpdate(final boolean state) { logger.debug("triggerUpdate - state: {}, lastState: {}", state, this.lastState); if (this.lastState == state) { return; } this.lastState = state; if (state) { this.listener.ready(Collections.unmodifiableList(this.dependencyHandles)); } else { this.listener.notReady(); } } private boolean isReady() { for (final Handle dep : this.dependencyHandles) { boolean satisfied = dep.isSatisfied(); logger.debug("Dependency - {}, satisied: {}", dep, satisfied); if (!satisfied) { return false; } } return true; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/EmptyRoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; public class EmptyRoutesProvider implements RoutesProvider { public static final EmptyRoutesProvider INSTANCE = new EmptyRoutesProvider(); private EmptyRoutesProvider() { } @Override public void applyRoutes(final CamelContext camelContext) throws Exception { CamelRunner.removeRoutes(camelContext, CamelRunner.fromRoutes(camelContext.getRoutes())); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/RegistryFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.spi.Registry; public interface RegistryFactory { public Registry createRegistry(); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/RoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import org.apache.camel.CamelContext; @FunctionalInterface public interface RoutesProvider { /** * Apply the desired state of camel routes to the context *

* Note: This method may need to stop and remove * routes which are no longer used *

* * @param camelContext * the context the routes should by applied to * @throws Exception * if anything goes wrong */ public void applyRoutes(CamelContext camelContext) throws Exception; } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ScriptRunner.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.util.Objects; import java.util.concurrent.Callable; import javax.script.Bindings; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; /** * A runner for scripts which takes care of class loader issues in OSGi *
* This class helps running java.script script inside an OSGi container. * There are some oddities of Rhino and Nashorn this runner takes care of * so that at least the standard "JavaScript" language works inside of OSGi. *
* In order to execute a script use: *
 * ScriptRunner runner = ScriptRunner.create(ServiceClass.class.getClassLoader(), "JavaScript", "callFooBar();" );
 * runner.run();
 * 
*/ public abstract class ScriptRunner { private static class EvalScriptRunner extends ScriptRunner { private final ClassLoader classLoader; private final ScriptEngine engine; private final String script; public EvalScriptRunner(final ClassLoader classLoader, final ScriptEngine engine, final String script) { this.classLoader = classLoader; this.engine = engine; this.script = script; } @Override public Object run() throws ScriptException { return runWithClassLoader(this.classLoader, new Callable() { @Override public Object call() throws Exception { return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script); } }); } @Override public Object run(final Bindings bindings) throws ScriptException { return runWithClassLoader(this.classLoader, new Callable() { @Override public Object call() throws Exception { return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script, bindings); } }); } @Override public Object run(final ScriptContext context) throws ScriptException { return runWithClassLoader(this.classLoader, new Callable() { @Override public Object call() throws Exception { return EvalScriptRunner.this.engine.eval(EvalScriptRunner.this.script, context); } }); } } private ScriptRunner() { } public abstract Object run() throws ScriptException; public abstract Object run(Bindings bindings) throws ScriptException; public abstract Object run(ScriptContext context) throws ScriptException; public static ScriptRunner create(final ClassLoader classLoader, final String scriptEngineName, final String script) throws ScriptException { final ScriptEngine engine = createEngine(classLoader, scriptEngineName); return new EvalScriptRunner(classLoader, engine, script); } private static ScriptEngineManager createManager(final ClassLoader classLoader) throws ScriptException { return runWithClassLoader(classLoader, new Callable() { @Override public ScriptEngineManager call() throws Exception { // passing null here since this will trigger // the script engine lookup to use java basic // support for JavaScript return new ScriptEngineManager(null); } }); } private static ScriptEngine createEngine(final ClassLoader classLoader, final ScriptEngineManager manager, final String engineName) throws ScriptException { Objects.requireNonNull(manager); Objects.requireNonNull(engineName); return runWithClassLoader(classLoader, new Callable() { @Override public ScriptEngine call() throws Exception { return manager.getEngineByName(engineName); } }); } private static ScriptEngine createEngine(final ClassLoader classLoader, final String engineName) throws ScriptException { return createEngine(classLoader, createManager(classLoader), engineName); } /** * Run a Callable while swapping the context class loader * * @param classLoader * the class loader to set while calling the code * @param code * the code to call * @return the return value of the code * @throws ScriptException * if anything goes wrong */ public static T runWithClassLoader(final ClassLoader classLoader, final Callable code) throws ScriptException { if (classLoader == null) { try { return code.call(); } catch (ScriptException e) { throw e; } catch (Exception e) { throw new ScriptException(e); } } final ClassLoader ccl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classLoader); try { return code.call(); } catch (ScriptException e) { throw e; } catch (Exception e) { throw new ScriptException(e); } finally { Thread.currentThread().setContextClassLoader(ccl); } } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ServiceConsumer.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; @FunctionalInterface public interface ServiceConsumer { public void consume(C context, T service); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/ServiceDependency.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; public interface ServiceDependency { public interface Handle { public void stop(); public boolean isSatisfied(); public void consume(C context); } public Handle start(Runnable runnable); } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/SimpleRoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.util.Objects; import org.apache.camel.CamelContext; import org.apache.camel.model.RoutesDefinition; public class SimpleRoutesProvider extends AbstractRoutesProvider { private final RoutesDefinition routes; public SimpleRoutesProvider(RoutesDefinition routes) { Objects.requireNonNull(routes); this.routes = routes; } @Override protected RoutesDefinition getRoutes(final CamelContext camelContext) throws Exception { return this.routes; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/XmlRoutesProvider.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.runner; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Reader; import java.nio.charset.StandardCharsets; import java.util.Objects; import java.util.function.Supplier; import org.apache.camel.CamelContext; import org.apache.camel.model.RoutesDefinition; import org.apache.commons.io.input.ReaderInputStream; public class XmlRoutesProvider extends AbstractRoutesProvider { private final Supplier inputStreamProvider; public XmlRoutesProvider(final String xml) { Objects.requireNonNull(xml); this.inputStreamProvider = () -> new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); } private XmlRoutesProvider(final Supplier inputStreamProvider) { Objects.requireNonNull(inputStreamProvider); this.inputStreamProvider = inputStreamProvider; } @Override protected RoutesDefinition getRoutes(final CamelContext camelContext) throws Exception { try (final InputStream in = this.inputStreamProvider.get()) { return camelContext.loadRoutesDefinition(in); } } public static XmlRoutesProvider fromString(final String xml) { return new XmlRoutesProvider(xml); } public static XmlRoutesProvider fromReader(final Supplier reader) { Objects.requireNonNull(reader); return new XmlRoutesProvider(() -> new ReaderInputStream(reader.get(), StandardCharsets.UTF_8)); } public static XmlRoutesProvider fromInputStream(final Supplier inputStream) { return new XmlRoutesProvider(inputStream); } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/runner/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Functionality for running a Camel context *

* The main class to create, run and update a {@link org.apache.camel.CamelContext} * is the {@link org.eclipse.kura.camel.runner.CamelRunner} which * is being created using a {@link org.eclipse.kura.camel.runner.CamelRunner.Builder} *

*/ package org.eclipse.kura.camel.runner; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/type/TypeConverter.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.type; import static org.eclipse.kura.type.TypedValues.newTypedValue; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.camel.Converter; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.type.TypedValue; import org.eclipse.kura.wire.WireEnvelope; import org.eclipse.kura.wire.WireRecord; @Converter public final class TypeConverter { private static final WireRecord[] EMPTY_RECORDS = new WireRecord[0]; private TypeConverter() { } @Converter public static KuraPayload fromMap(final Map data) { if (data == null) { return null; } final KuraPayload result = new KuraPayload(); result.setTimestamp(new Date()); for (final Map.Entry entry : data.entrySet()) { result.addMetric(entry.getKey(), entry.getValue()); } return result; } @Converter public static WireRecord[] recordsFromEnvelope(final WireEnvelope envelope) { return recordsFromList(envelope.getRecords()); } @Converter public static WireRecord[] recordsFromRecord(final WireRecord record) { return new WireRecord[] { record }; } @Converter public static WireRecord[] recordsFromList(final List records) { return records.toArray(new WireRecord[records.size()]); } @Converter public static WireRecord[] recordsFromMap(final Map map) { if (map.isEmpty()) { return EMPTY_RECORDS; } final Map> result = new HashMap<>(); for (final Map.Entry entry : map.entrySet()) { final Object keyValue = entry.getKey(); if (keyValue == null) { continue; } if (entry.getValue() instanceof TypedValue) { result.put(keyValue.toString(), (TypedValue) entry.getValue()); } else { result.put(keyValue.toString(), newTypedValue(entry.getValue())); } } return recordsFromRecord(new WireRecord(result)); } @Converter public static Map mapFromRecord(final WireRecord record) { final Map result = new HashMap<>(record.getProperties().size()); for (final Map.Entry> entry : record.getProperties().entrySet()) { result.put(entry.getKey(), entry.getValue().getValue()); } return result; } @Converter public static Map mapFromRecords(final WireRecord[] records) { final Map result = new HashMap<>(); for (final WireRecord record : records) { for (final Map.Entry> entry : record.getProperties().entrySet()) { result.put(entry.getKey(), entry.getValue().getValue()); } } return result; } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/type/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Type converters for Camel */ package org.eclipse.kura.camel.type; ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/utils/CamelContexts.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.utils; import static org.eclipse.kura.camel.runner.ScriptRunner.create; import javax.script.ScriptException; import javax.script.SimpleBindings; import org.apache.camel.CamelContext; import org.eclipse.kura.camel.runner.ScriptRunner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class CamelContexts { private static final Logger logger = LoggerFactory.getLogger(CamelContexts.class); private CamelContexts() { } /** * Run an init script on a camel context * * @param context * the context to work on * @param initCode * the init code, may be {@code null} or empty * @param classLoader * the classloader to use for the script engine, may be {@code null} * @throws ScriptException * if calling the script fails */ public static void scriptInitCamelContext(final CamelContext context, final String initCode, final ClassLoader classLoader) throws ScriptException { // pre-flight check if (initCode == null || initCode.isEmpty()) { return; } try { // setup runner final ScriptRunner runner = create(classLoader, "JavaScript", initCode); // setup arguments final SimpleBindings bindings = new SimpleBindings(); bindings.put("camelContext", context); // perform call runner.run(bindings); } catch (final Exception e) { logger.warn("Failed to run init code", e); throw e; } } } ================================================ FILE: kura/org.eclipse.kura.camel/src/main/java/org/eclipse/kura/camel/utils/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * Camel utilities */ package org.eclipse.kura.camel.utils; ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/.gitignore ================================================ /bin/ ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Camel Cloud Factory Bundle-SymbolicName: org.eclipse.kura.camel.cloud.factory;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Bundle-ActivationPolicy: lazy Import-Package: javax.script, org.apache.camel;version="[2.17.0,3.0.0)", org.apache.camel.core.osgi;version="[2.17.0,3.0.0)", org.apache.camel.impl;version="[2.17.0,3.0.0)", org.apache.camel.model;version="[2.17.0,3.0.0)", org.apache.camel.support;version="[2.17.0,3.0.0)", org.eclipse.kura;version="[1.2,2.0)", org.eclipse.kura.camel.bean;version="[1.1,2.0)", org.eclipse.kura.camel.camelcloud;version="[1.1,2.0)", org.eclipse.kura.camel.cloud;version="[1.1,2.0)", org.eclipse.kura.camel.component;version="[1.1,2.0)", org.eclipse.kura.camel.runner;version="[1.1,2.0)", org.eclipse.kura.camel.utils;version="[1.1,2.0)", org.eclipse.kura.cloud;version="[1.0,2.0)", org.eclipse.kura.cloud.factory;version="[1.1,1.2)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.configuration.metatype;version="[1.1,2.0)", org.eclipse.kura.core.configuration;version="[2.0,3.0)", org.eclipse.kura.core.configuration.metatype;version="[1.0,2.0)", org.osgi.framework;version="1.7.0", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.7.0" Service-Component: OSGI-INF/factory.xml, OSGI-INF/serviceFactory.xml DynamicImport-Package: * ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/factory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/metatype/org.eclipse.kura.camel.cloud.factory.CamelFactory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/OSGI-INF/serviceFactory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/build.properties ================================================ output.. = target/classes bin.includes = META-INF/,\ .,\ about.html,\ OSGI-INF/ source.. = src/ ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.camel.cloud.factory 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.camel.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/CamelCloudServiceFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud.factory.internal; import static org.eclipse.kura.camel.cloud.factory.internal.CamelFactory.FACTORY_ID; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.TreeSet; import org.eclipse.kura.KuraException; import org.eclipse.kura.camel.component.Configuration; import org.eclipse.kura.cloud.factory.CloudServiceFactory; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An implementation of {@link CloudServiceFactory} based on Apache Camel */ public class CamelCloudServiceFactory implements CloudServiceFactory { private static final Logger logger = LoggerFactory.getLogger(CamelCloudServiceFactory.class); public static final String PID = "org.eclipse.kura.camel.cloud.factory.CamelCloudServiceFactory"; private ConfigurationService configurationService; public void setConfigurationService(final ConfigurationService configurationService) { this.configurationService = configurationService; } /** * Add a new CamelFactory * * @param userPid * the PID as entered by the user * @param properties * the provided configuration properties * @throws KuraException * if anything goes wrong */ protected void add(final String pid, final Map properties) throws KuraException { logger.info("Add: {}", pid); final Map props = new HashMap<>(); String xml = Configuration.asString(properties, "xml"); if (xml == null || xml.trim().isEmpty()) { xml = ""; } props.put("xml", xml); final Integer serviceRanking = Configuration.asInteger(properties, "serviceRanking"); if (serviceRanking != null) { props.put("serviceRanking", serviceRanking); } props.put("cloud.service.pid", pid); this.configurationService.createFactoryConfiguration(FACTORY_ID, fromUserPid(pid), props, true); } private static String fromUserPid(final String pid) { Objects.requireNonNull(pid); return pid + "-CloudFactory"; } private static String fromInternalPid(final String pid) { Objects.requireNonNull(pid); return pid.replaceAll("-CloudFactory$", ""); } /** * Enumerate all registered CamelFactory instances * * @return a PID (kura.service.pid) set of all registered CamelFactory instances */ public static Set lookupIds() { final Set ids = new TreeSet<>(); try { final Collection> refs = FrameworkUtil .getBundle(CamelCloudServiceFactory.class).getBundleContext() .getServiceReferences(CamelFactory.class, null); if (refs != null) { for (final ServiceReference ref : refs) { addService(ref, ids); } } } catch (final InvalidSyntaxException e) { } return ids; } private static void addService(final ServiceReference ref, final Set ids) { final Object kpid = ref.getProperty("kura.service.pid"); if (kpid instanceof String) { ids.add((String) kpid); } } /** * Provide a common way to delete camel factory configurations *

* Right now this is a rather slim implementation used by CamelFactory and the CamelManager *

* * @param configurationService * the configuration service to use * @param pid * the PID to delete */ static void delete(final ConfigurationService configurationService, final String pid) { try { configurationService.deleteFactoryConfiguration(pid, true); } catch (final KuraException e) { logger.warn("Failed to delete: {}", pid, e); } } @Override public void createConfiguration(final String pid) throws KuraException { add(pid, Collections.emptyMap()); } @Override public void deleteConfiguration(final String pid) throws KuraException { delete(this.configurationService, fromUserPid(pid)); } @Override public String getFactoryPid() { return FACTORY_ID; } @Override public List getStackComponentsPids(final String pid) throws KuraException { return Collections.singletonList(fromUserPid(pid)); } @Override public Set getManagedCloudServicePids() throws KuraException { final Set result = new HashSet<>(); for (final ComponentConfiguration cc : this.configurationService.getComponentConfigurations()) { if (cc.getDefinition() != null && FACTORY_ID.equals(cc.getDefinition().getId())) { result.add(fromInternalPid(cc.getPid())); } } return result; } } ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/CamelFactory.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc * Eurotech *******************************************************************************/ package org.eclipse.kura.camel.cloud.factory.internal; import static org.eclipse.kura.camel.component.Configuration.asBoolean; import static org.eclipse.kura.camel.component.Configuration.asString; import java.util.Map; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A Kura component which takes care of creating a {@link org.eclipse.kura.cloud.CloudService} based in Apache Camel *

* This component does not directly register as {@link org.eclipse.kura.cloud.CloudService}, but can be managed * through the Kura configuration system and will forward this configuration to the * {@link XmlCamelCloudService} which will take care of the lifecycle of the Camel context. *

*/ public class CamelFactory implements ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(CamelFactory.class); public static final String FACTORY_ID = "org.eclipse.kura.camel.cloud.factory.CamelFactory"; private XmlCamelCloudService service; private ServiceConfiguration configuration; public void activate(final Map properties) throws Exception { setFromProperties(properties); } public void modified(final Map properties) throws Exception { setFromProperties(properties); } private void setFromProperties(final Map properties) throws Exception { final String pid = asString(properties, "cloud.service.pid"); final ServiceConfiguration serviceConfiguration = new ServiceConfiguration(); serviceConfiguration.setXml(asString(properties, "xml")); serviceConfiguration.setInitCode(asString(properties, "initCode")); serviceConfiguration.setEnableJmx(asBoolean(properties, "enableJmx", true)); createService(pid, serviceConfiguration); } public void deactivate() { if (this.service != null) { try { this.service.stop(); } catch (Exception e) { logger.warn("Failed to stop", e); } this.service = null; } } private void createService(final String pid, final ServiceConfiguration configuration) throws Exception { if (pid == null) { return; } if (this.configuration == configuration) { // null to null? return; } if (this.configuration != null && this.configuration.equals(configuration)) { // no change return; } // stop old service if (this.service != null) { this.service.stop(); this.service = null; } // start new service if (configuration.isValid()) { this.service = new XmlCamelCloudService(FrameworkUtil.getBundle(CamelFactory.class).getBundleContext(), pid, configuration); this.service.start(); } this.configuration = configuration; } } ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/ServiceConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud.factory.internal; /** * The configuration of a Camel based {@link org.eclipse.kura.cloud.CloudService} instance */ public class ServiceConfiguration { private String xml; private String initCode; private boolean enableJmx; /** * Set the router XML * * @param xml * must not be {@code null} */ public void setXml(String xml) { this.xml = xml; } public String getXml() { return this.xml; } public void setInitCode(String initCode) { this.initCode = initCode; } public String getInitCode() { return this.initCode; } public void setEnableJmx(boolean enableJmx) { this.enableJmx = enableJmx; } public boolean isEnableJmx() { return enableJmx; } public boolean isValid() { if (this.xml == null || this.xml.trim().isEmpty()) { return false; } return true; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.enableJmx ? 1231 : 1237); result = prime * result + (this.initCode == null ? 0 : this.initCode.hashCode()); result = prime * result + (this.xml == null ? 0 : this.xml.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ServiceConfiguration other = (ServiceConfiguration) obj; if (this.enableJmx != other.enableJmx) { return false; } if (this.initCode == null) { if (other.initCode != null) { return false; } } else if (!this.initCode.equals(other.initCode)) { return false; } if (this.xml == null) { if (other.xml != null) { return false; } } else if (!this.xml.equals(other.xml)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.camel.cloud.factory/src/org/eclipse/kura/camel/cloud/factory/internal/XmlCamelCloudService.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.cloud.factory.internal; import static org.apache.camel.ServiceStatus.Started; import static org.eclipse.kura.camel.cloud.factory.internal.CamelCloudServiceFactory.PID; import static org.eclipse.kura.camel.cloud.factory.internal.CamelFactory.FACTORY_ID; import static org.eclipse.kura.camel.utils.CamelContexts.scriptInitCamelContext; import static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID; import static org.osgi.framework.Constants.SERVICE_PID; import java.io.ByteArrayInputStream; import java.util.Dictionary; import java.util.Hashtable; import javax.script.ScriptException; import org.apache.camel.CamelContext; import org.apache.camel.ServiceStatus; import org.apache.camel.core.osgi.OsgiDefaultCamelContext; import org.apache.camel.core.osgi.OsgiServiceRegistry; import org.apache.camel.impl.CompositeRegistry; import org.apache.camel.impl.SimpleRegistry; import org.apache.camel.model.RoutesDefinition; import org.eclipse.kura.camel.bean.PayloadFactory; import org.eclipse.kura.camel.camelcloud.DefaultCamelCloudService; import org.eclipse.kura.camel.cloud.KuraCloudComponent; import org.eclipse.kura.cloud.CloudService; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An service managing a single Camel context as {@link CloudService} *

* This service component does manage the lifecycle of a single {@link DefaultCamelCloudService} * instance. It will instantiate the Camel context and register the {@link CloudService} instance * with OSGi. *

*/ public class XmlCamelCloudService { private static final Logger logger = LoggerFactory.getLogger(XmlCamelCloudService.class); private final BundleContext context; private final String pid; private final ServiceConfiguration configuration; private DefaultCamelCloudService service; private OsgiDefaultCamelContext router; private ServiceRegistration handle; public XmlCamelCloudService(final BundleContext context, final String pid, final ServiceConfiguration configuration) { this.context = context; this.pid = pid; this.configuration = configuration; } public void start() throws Exception { // new registry final SimpleRegistry simpleRegistry = new SimpleRegistry(); simpleRegistry.put("payloadFactory", new PayloadFactory()); final CompositeRegistry registry = new CompositeRegistry(); registry.addRegistry(new OsgiServiceRegistry(this.context)); registry.addRegistry(simpleRegistry); // new router this.router = new OsgiDefaultCamelContext(this.context, registry); if (!configuration.isEnableJmx()) { this.router.disableJMX(); } // call init code callInitCode(this.router); // new cloud service this.service = new DefaultCamelCloudService(this.router); // set up final KuraCloudComponent cloudComponent = new KuraCloudComponent(this.router, this.service); this.router.addComponent("kura-cloud", cloudComponent); final RoutesDefinition routesDefinition = this.router .loadRoutesDefinition(new ByteArrayInputStream(this.configuration.getXml().getBytes())); this.router.addRouteDefinitions(routesDefinition.getRoutes()); // start logger.debug("Starting router..."); this.router.start(); final ServiceStatus status = this.router.getStatus(); logger.debug("Starting router... {} ({}, {})", status, status == Started, this.service.isConnected()); // register final Dictionary props = new Hashtable<>(); props.put(SERVICE_PID, this.pid); props.put("service.factoryPid", FACTORY_ID); props.put(KURA_SERVICE_PID, this.pid); props.put("kura.cloud.service.factory.pid", PID); this.handle = this.context.registerService(CloudService.class, this.service, props); } public void stop() throws Exception { if (this.handle != null) { this.handle.unregister(); this.handle = null; } if (this.service != null) { this.service.dispose(); this.service = null; } if (this.router != null) { this.router.stop(); this.router = null; } } private void callInitCode(final CamelContext router) throws ScriptException { scriptInitCamelContext(router, configuration.getInitCode(), XmlCamelCloudService.class.getClassLoader()); } } ================================================ FILE: kura/org.eclipse.kura.camel.xml/.gitignore ================================================ /bin/ ================================================ FILE: kura/org.eclipse.kura.camel.xml/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Plain XML router component Bundle-SymbolicName: org.eclipse.kura.camel.xml Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: org.apache.camel;version="[2.17.0,3.0.0)", org.eclipse.kura.camel.bean;version="[1.1,2.0)", org.eclipse.kura.camel.component;version="[1.1,2.0)", org.eclipse.kura.camel.runner;version="[1.1,2.0)", org.eclipse.kura.camel.utils;version="[1.1,2.0)", org.eclipse.kura.cloud;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.message;version="[1.0,2.0)", org.osgi.framework;version="1.7.0", org.slf4j;version="1.7.0" Service-Component: OSGI-INF/xmlRouter.xml Bundle-ActivationPolicy: lazy DynamicImport-Package: * ================================================ FILE: kura/org.eclipse.kura.camel.xml/OSGI-INF/metatype/org.eclipse.kura.camel.xml.XmlRouterComponent.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel.xml/OSGI-INF/xmlRouter.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.camel.xml/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.camel.xml/build.properties ================================================ output.. = target/classes source.. = src/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html ================================================ FILE: kura/org.eclipse.kura.camel.xml/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.camel.xml 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ================================================ FILE: kura/org.eclipse.kura.camel.xml/src/org/eclipse/kura/camel/xml/XmlRouterComponent.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.camel.xml; import static java.lang.String.format; import static org.eclipse.kura.camel.component.Configuration.asBoolean; import static org.eclipse.kura.camel.component.Configuration.asString; import static org.eclipse.kura.camel.runner.CamelRunner.createOsgiRegistry; import static org.eclipse.kura.camel.utils.CamelContexts.scriptInitCamelContext; import static org.osgi.framework.FrameworkUtil.getBundle; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.eclipse.kura.camel.bean.PayloadFactory; import org.eclipse.kura.camel.component.AbstractXmlCamelComponent; import org.eclipse.kura.camel.component.Configuration; import org.eclipse.kura.camel.runner.CamelRunner.Builder; import org.eclipse.kura.cloud.CloudService; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A ready to run XML based Apache Camel component * * @noextend This class is not intended to be extended */ public class XmlRouterComponent extends AbstractXmlCamelComponent { private static final String TOKEN_PATTERN = "\\s*,\\s*"; private static final Logger logger = LoggerFactory.getLogger(XmlRouterComponent.class); private static final String CLOUD_SERVICE_PREREQS = "cloudService.prereqs"; private static final String COMPONENT_PREREQS = "component.prereqs"; private static final String LANGUAGE_PREREQS = "language.prereqs"; private static final String DISABLE_JMX = "disableJmx"; private static final String INIT_CODE = "initCode"; private final BundleContext bundleContext; private Set requiredComponents = new HashSet<>(); private Set requiredLanguages = new HashSet<>(); private Map cloudServiceRequirements = new HashMap<>(); private String initCode = ""; private boolean disableJmx; public XmlRouterComponent() { super("xml.data"); this.bundleContext = FrameworkUtil.getBundle(XmlRouterComponent.class).getBundleContext(); } @Override protected void customizeBuilder(final Builder builder, final Map properties) { // JMX final boolean disableJmxTemp = asBoolean(properties, DISABLE_JMX, false); builder.disableJmx(disableJmxTemp); // parse configuration final Set newRequiredComponents = parseRequirements(asString(properties, COMPONENT_PREREQS)); final Set newRequiredLanguages = parseRequirements(asString(properties, LANGUAGE_PREREQS)); final Map cloudServiceRequirementsTemp = parseCloudServiceRequirements( asString(properties, CLOUD_SERVICE_PREREQS)); final String initCodeTemp = parseInitCode(properties); // set component requirements logger.debug("Setting new component requirements"); for (final String component : newRequiredComponents) { logger.debug("Require component: {}", component); builder.requireComponent(component); } logger.debug("Setting new language requirements"); for (final String language : newRequiredLanguages) { logger.debug("Require language: {}", language); builder.requireLanguage(language); } // set cloud service requirements logger.debug("Setting new cloud service requirements"); for (final Map.Entry entry : cloudServiceRequirementsTemp.entrySet()) { final String filter; if (entry.getValue().startsWith("(")) { filter = entry.getValue(); } else { filter = format("(&(%s=%s)(kura.service.pid=%s))", Constants.OBJECTCLASS, CloudService.class.getName(), entry.getValue()); } builder.cloudService(null, filter, Builder.addAsCloudComponent(entry.getKey())); } if (!initCodeTemp.isEmpty()) { // call init code before context start builder.addBeforeStart(camelContext -> { scriptInitCamelContext(camelContext, initCodeTemp, XmlRouterComponent.class.getClassLoader()); }); } // build registry final BundleContext ctx = getBundle(XmlRouterComponent.class).getBundleContext(); final Map services = new HashMap<>(); services.put("payloadFactory", new PayloadFactory()); builder.registryFactory(createOsgiRegistry(ctx, services)); // assign new state this.requiredComponents = newRequiredComponents; this.requiredLanguages = newRequiredLanguages; this.cloudServiceRequirements = cloudServiceRequirementsTemp; this.initCode = initCodeTemp; this.disableJmx = disableJmxTemp; } @Override protected boolean isRestartNeeded(final Map properties) { final boolean disableJmxTemp = asBoolean(properties, DISABLE_JMX, false); final Set newRequiredComponents = parseRequirements(asString(properties, COMPONENT_PREREQS)); final Map cloudServiceRequirementsTemp = parseCloudServiceRequirements( asString(properties, CLOUD_SERVICE_PREREQS)); final String initCodeTemp = parseInitCode(properties); if (this.disableJmx != disableJmxTemp) { logger.debug("Require restart due to '{}' change", DISABLE_JMX); return true; } if (!this.requiredComponents.equals(newRequiredComponents)) { logger.debug("Require restart due to '{}' change", COMPONENT_PREREQS); return true; } if (!this.requiredLanguages.equals(newRequiredComponents)) { logger.debug("Require restart due to '{}' change", LANGUAGE_PREREQS); return true; } if (!this.cloudServiceRequirements.equals(cloudServiceRequirementsTemp)) { logger.debug("Require restart due to '{}' change", CLOUD_SERVICE_PREREQS); return true; } if (!this.initCode.equals(initCodeTemp)) { logger.debug("Require restart due to '{}' change", INIT_CODE); return true; } return false; } private static Map parseCloudServiceRequirements(final String value) { if (value == null || value.trim().isEmpty()) { return Collections.emptyMap(); } final Map result = new HashMap<>(); for (final String tok : value.split(TOKEN_PATTERN)) { logger.debug("Testing - '{}'", tok); final String[] s = tok.split("=", 2); if (s.length != 2) { continue; } logger.debug("CloudService - '{}' -> '{}'", s[0], s[1]); result.put(s[0], s[1]); } return result; } private static Set parseRequirements(final String value) { if (value == null || value.trim().isEmpty()) { return Collections.emptySet(); } return new HashSet<>(Arrays.asList(value.split(TOKEN_PATTERN))); } private static String parseInitCode(final Map properties) { return Configuration.asString(properties, INIT_CODE, ""); } @Override protected BundleContext getBundleContext() { return this.bundleContext; } } ================================================ FILE: kura/org.eclipse.kura.camel.xml/src/org/eclipse/kura/camel/xml/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Red Hat Inc and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Red Hat Inc *******************************************************************************/ /** * A ready-to-run Apache Camel XML router component */ package org.eclipse.kura.camel.xml; ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.cloud.base.provider Bundle-SymbolicName: org.eclipse.kura.cloud.base.provider;singleton:=true Bundle-Version: 1.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.core.data;version="1.3.0", org.eclipse.kura.core.data.util;version="1.0.0";x-internal:=true Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.connection.listener;version="[1.0,2.0)", org.eclipse.kura.core.util;version="[2.0,3.0)", org.eclipse.kura.crypto;version="[1.3,2.0)", org.eclipse.kura.data;version="[1.1,2.0)", org.eclipse.kura.data.listener;version="[1.0,2.0)", org.eclipse.kura.data.transport.listener;version="[1.0,2.0)", org.eclipse.kura.db;version="[2.0,3.0)", org.eclipse.kura.message.store;version="[1.0,2.0)", org.eclipse.kura.message.store.provider;version="[1.0,1.1)", org.eclipse.kura.ssl;version="[2.1,3.0)", org.eclipse.kura.status;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.4,2.0)", org.eclipse.kura.util.message.store;version="[1.0,1.1)", org.eclipse.kura.util.store.listener;version="[1.0,2.0)", org.eclipse.kura.watchdog;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.4.0", org.osgi.util.tracker;version="1.5.0", org.quartz;version="2.3.2", org.slf4j;version="1.6.4" Bundle-ClassPath: ., lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/data.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/metatype/org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/metatype/org.eclipse.kura.data.DataService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/OSGI-INF/mqttDataTransport.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/build.properties ================================================ # # Copyright (c) 2024 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/,\ src/main/resources/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar additional.bundles = slf4j.api,\ org.eclipse.osgi,\ org.eclipse.equinox.io,\ org.eclipse.kura.api,\ org.apache.logging.log4j.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml org.eclipse.paho org.eclipse.paho.client.mqttv3 org.eclipse.kura.cloud.base.provider 1.0.0-SNAPSHOT eclipse-plugin ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/AlwaysConnectedStrategy.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.data; public class AlwaysConnectedStrategy implements AutoConnectStrategy { private final ConnectionManager connectionManager; public AlwaysConnectedStrategy(final ConnectionManager connectionManager) { this.connectionManager = connectionManager; connectionManager.startConnectionTask(); } @Override public void onConnectionEstablished() { // do nothing } @Override public void onDisconnecting() { // do nothing } @Override public void onDisconnected() { connectionManager.startConnectionTask(); } @Override public void onConnectionLost(Throwable cause) { connectionManager.stopConnectionTask(); connectionManager.startConnectionTask(); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { // do nothing } @Override public void onMessagePublished(int messageId, String topic) { // do nothing } @Override public void onMessageConfirmed(int messageId, String topic) { // do nothing } @Override public void shutdown() { connectionManager.stopConnectionTask(); } @Override public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority) { // do nothing } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/AutoConnectStrategy.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.data; import java.util.Optional; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.message.store.StoredMessage; interface AutoConnectStrategy extends DataServiceListener { public void shutdown(); public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority); interface ConnectionManager { void startConnectionTask(); void stopConnectionTask(); void disconnect(); Optional getNextMessage(); boolean hasInFlightMessages(); boolean isConnected(); } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataMessage.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data; import java.util.Arrays; import java.util.Date; /** * DataMessage is a message that is currently transiting through the DataService. * It is a wrapper class over the message payload as produced by the client application * but it also capture all the state information of the message through its * DataService life-cycle of: stored -> published -> confirmed. */ public class DataMessage { private int id; private String topic; private int qos; private boolean retain; private Date createdOn; private Date publishedOn; private int publishedMessageId; private Date confirmedOn; private byte[] payload; private int priority; private String sessionId; private Date droppedOn; public DataMessage() { } public DataMessage(Builder b) { this.id = b.id; this.topic = b.topic; this.qos = b.qos; this.retain = b.retain; this.createdOn = b.createdOn; this.publishedOn = b.publishedOn; this.publishedMessageId = b.publishedMessageId; this.confirmedOn = b.confirmedOn; this.payload = b.payload; this.priority = b.priority; this.sessionId = b.sessionId; this.droppedOn = b.droppedOn; } public int getId() { return this.id; } public String getTopic() { return this.topic; } public int getQos() { return this.qos; } public boolean isRetain() { return this.retain; } public Date getCreatedOn() { return this.createdOn; } public Date getPublishedOn() { return this.publishedOn; } public int getPublishedMessageId() { return this.publishedMessageId; } public void setPublishedMessageId(int publishedMessageId) { this.publishedMessageId = publishedMessageId; } public Date getConfirmedOn() { return this.confirmedOn; } public byte[] getPayload() { return this.payload; } public int getPriority() { return this.priority; } public String getSessionId() { return this.sessionId; } public Date droppedOn() { return this.droppedOn; } @Override public String toString() { StringBuilder builder = new StringBuilder("DataMessage [id=").append(this.id).append(", topic=") .append(this.topic).append(", qos=").append(this.qos).append(", retain=").append(this.retain) .append(", createdOn=").append(this.createdOn).append(", publishedOn=").append(this.publishedOn) .append(", publishedMessageId=").append(this.publishedMessageId).append(", confirmedOn=") .append(this.confirmedOn).append(", payload=").append(Arrays.toString(this.payload)) .append(", priority=").append(this.priority).append(", sessionId=").append(this.sessionId) .append(", droppedOn=").append(this.droppedOn).append("]"); return builder.toString(); } public static class Builder { private final int id; private String topic; private int qos; private boolean retain; private Date createdOn; private Date publishedOn; private int publishedMessageId; private Date confirmedOn; private byte[] payload; private int priority; private String sessionId; private Date droppedOn; public Builder(int id) { this.id = id; } public Builder withTopic(String topic) { this.topic = topic; return this; } public Builder withQos(int qos) { this.qos = qos; return this; } public Builder withRetain(boolean retain) { this.retain = retain; return this; } public Builder withCreatedOn(Date createdOn) { this.createdOn = createdOn; return this; } public Builder withPublishedOn(Date publishedOn) { this.publishedOn = publishedOn; return this; } public Builder withPublishedMessageId(int publishedMessageId) { this.publishedMessageId = publishedMessageId; return this; } public Builder withConfirmedOn(Date confirmedOn) { this.confirmedOn = confirmedOn; return this; } public Builder withPayload(byte[] payload) { this.payload = payload; return this; } public Builder withPriority(int priority) { this.priority = priority; return this; } public Builder withSessionId(String sessionId) { this.sessionId = sessionId; return this; } public Builder withDroppedOn(Date droppedOn) { this.droppedOn = droppedOn; return this; } public int getId() { return this.id; } public String getTopic() { return this.topic; } public int getQos() { return this.qos; } public boolean getRetain() { return this.retain; } public Date getCreatedOn() { return this.createdOn; } public Date getPublishedOn() { return this.publishedOn; } public int getPublishedMessageId() { return this.publishedMessageId; } public Date getConfirmedOn() { return this.confirmedOn; } public byte[] getPayload() { return this.payload; } public int getPriority() { return this.priority; } public String getSessionId() { return this.sessionId; } public Date getDroppedOn() { return this.droppedOn; } public DataMessage build() { return new DataMessage(this); } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.KuraStoreCapacityReachedException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.KuraTooManyInflightMessagesException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.connection.listener.ConnectionListener; import org.eclipse.kura.core.data.store.MessageStoreState; import org.eclipse.kura.core.internal.data.TokenBucket; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.DataTransportService; import org.eclipse.kura.data.DataTransportToken; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.eclipse.kura.message.store.StoredMessage; import org.eclipse.kura.message.store.provider.MessageStore; import org.eclipse.kura.message.store.provider.MessageStoreProvider; import org.eclipse.kura.status.CloudConnectionStatusComponent; import org.eclipse.kura.status.CloudConnectionStatusEnum; import org.eclipse.kura.status.CloudConnectionStatusService; import org.eclipse.kura.watchdog.CriticalComponent; import org.eclipse.kura.watchdog.WatchdogService; import org.eclipse.paho.client.mqttv3.MqttException; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentException; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.quartz.CronExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DataServiceImpl implements DataService, DataTransportListener, ConfigurableComponent, CloudConnectionStatusComponent, CriticalComponent, AutoConnectStrategy.ConnectionManager, ConnectionListener { private static final String MESSAGE_STORE_NOT_CONNECTED_MESSAGE = "Message store instance not connected, not connecting"; public static final String MESSAGE_STORE_NOT_PRESENT_MESSAGE = "Message store instance not configured properly, not connecting"; private static final int RECONNECTION_MIN_DELAY = 1; private static final Logger logger = LoggerFactory.getLogger(DataServiceImpl.class); private static final int TRANSPORT_TASK_TIMEOUT = 1; // In seconds private DataServiceOptions dataServiceOptions; private DataTransportService dataTransportService; private DataServiceListenerS dataServiceListeners; protected ScheduledExecutorService connectionMonitorExecutor; private ScheduledFuture connectionMonitorFuture; // A dedicated executor for the publishing task private ExecutorService publisherExecutor; private Optional storeState = Optional.empty(); private Map inFlightMsgIds = new ConcurrentHashMap<>(); private ScheduledExecutorService congestionExecutor; private ScheduledFuture congestionFuture; private CloudConnectionStatusService cloudConnectionStatusService; private CloudConnectionStatusEnum notificationStatus = CloudConnectionStatusEnum.OFF; private TokenBucket throttle; private final Lock lock = new ReentrantLock(); private boolean notifyPending; private final Condition lockCondition = this.lock.newCondition(); private final AtomicBoolean publisherEnabled = new AtomicBoolean(); private ServiceTracker dbServiceTracker; private ComponentContext componentContext; private WatchdogService watchdogService; private AtomicInteger connectionAttempts; private Optional autoConnectStrategy = Optional.empty(); private final Random random = new SecureRandom(); private AtomicBoolean disconnectionGuard = new AtomicBoolean(); // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map properties) { String pid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("Activating {}...", pid); this.componentContext = componentContext; this.dataServiceOptions = new DataServiceOptions(properties); this.connectionMonitorExecutor = Executors.newSingleThreadScheduledExecutor(); this.publisherExecutor = Executors.newSingleThreadExecutor(); this.congestionExecutor = Executors.newSingleThreadScheduledExecutor(); createThrottle(); submitPublishingWork(); restartDbServiceTracker(this.dataServiceOptions.getDbServiceInstancePid()); this.dataServiceListeners = new DataServiceListenerS(componentContext); // Register the component in the CloudConnectionStatus Service this.cloudConnectionStatusService.register(this); this.dataTransportService.addDataTransportListener(this); createAutoConnectStrategy(); } private void restartDbServiceTracker(String kuraServicePid) { stopDbServiceTracker(); try { final Filter filter = FrameworkUtil .createFilter("(" + ConfigurationService.KURA_SERVICE_PID + "=" + kuraServicePid + ")"); this.dbServiceTracker = new ServiceTracker<>(this.componentContext.getBundleContext(), filter, new ServiceTrackerCustomizer() { @Override public Object addingService(ServiceReference reference) { logger.info("Message store instance found"); Object service = DataServiceImpl.this.componentContext.getBundleContext() .getService(reference); if (service instanceof MessageStoreProvider) { setMessageStoreProvider((MessageStoreProvider) service); } else { DataServiceImpl.this.componentContext.getBundleContext().ungetService(reference); return null; } return service; } @Override public void modifiedService(ServiceReference reference, Object service) { if (service instanceof MessageStoreProvider) { return; } logger.info("Message store instance updated, recreating table if needed..."); synchronized (DataServiceImpl.this) { if (DataServiceImpl.this.storeState.isPresent()) { DataServiceImpl.this.storeState.get() .update(DataServiceImpl.this.dataServiceOptions); } } } @Override public void removedService(ServiceReference reference, Object service) { logger.info("Message store instance removed"); unsetMessageStoreProvider(); DataServiceImpl.this.componentContext.getBundleContext().ungetService(reference); } }); this.dbServiceTracker.open(); } catch (InvalidSyntaxException e) { throw new ComponentException(e); } } private void stopDbServiceTracker() { if (this.dbServiceTracker != null) { this.dbServiceTracker.close(); this.dbServiceTracker = null; } } private synchronized void startDbStore() { try { List inFlightMsgs = Collections.emptyList(); // The initial list of in-flight messages if (DataServiceImpl.this.storeState.isPresent()) { inFlightMsgs = this.storeState.get().getOrOpenMessageStore().getInFlightMessages(); } // The map associating a DataTransportToken with a message ID this.inFlightMsgIds = new ConcurrentHashMap<>(); if (inFlightMsgs != null) { for (StoredMessage message : inFlightMsgs) { final Optional token = message.getDataTransportToken(); if (!token.isPresent()) { logger.warn("In-flight message has no associated DataTransportToken"); continue; } this.inFlightMsgIds.put(token.get(), message.getId()); logger.debug("Restored in-fligh messages from store. Topic: {}, ID: {}, MQTT message ID: {}", message.getTopic(), message.getId(), token.get().getMessageId()); } } } catch (KuraStoreException e) { logger.error("Failed to start store", e); DataServiceImpl.this.disconnectDataTransportAndLog(e); } } public synchronized void updated(Map properties) { logger.info("Updating {}...", properties.get(ConfigurationService.KURA_SERVICE_PID)); shutdownAutoConnectStrategy(); stopConnectionTask(); final String oldDbServicePid = this.dataServiceOptions.getDbServiceInstancePid(); this.dataServiceOptions = new DataServiceOptions(properties); createThrottle(); final String currentDbServicePid = this.dataServiceOptions.getDbServiceInstancePid(); if (oldDbServicePid.equals(currentDbServicePid)) { if (DataServiceImpl.this.storeState.isPresent()) { this.storeState.get().update(this.dataServiceOptions); } } else { restartDbServiceTracker(currentDbServicePid); } createAutoConnectStrategy(); } protected void deactivate(ComponentContext componentContext) { logger.info("Deactivating {}...", this.dataServiceOptions.getKuraServicePid()); shutdownAutoConnectStrategy(); this.connectionMonitorExecutor.shutdownNow(); this.congestionExecutor.shutdownNow(); disconnect(); // Await termination of the publisher executor tasks try { // Waits to publish latest messages e.g. disconnect message Thread.sleep(TRANSPORT_TASK_TIMEOUT * 1000L); // Clean publisher thread shutdown this.publisherEnabled.set(false); signalPublisher(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.info("Interrupted", e); } this.publisherExecutor.shutdownNow(); this.dataTransportService.removeDataTransportListener(this); if (storeState.isPresent()) { this.storeState.get().shutdown(); } stopDbServiceTracker(); } // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setDataTransportService(DataTransportService dataTransportService) { this.dataTransportService = dataTransportService; } public void unsetDataTransportService(DataTransportService dataTransportService) { this.dataTransportService = null; } public synchronized void setMessageStoreProvider(MessageStoreProvider messageStoreProvider) { this.storeState = Optional.of(new MessageStoreState(messageStoreProvider, this.dataServiceOptions)); messageStoreProvider.addListener(this); startDbStore(); signalPublisher(); } public synchronized void unsetMessageStoreProvider() { disconnect(); if (this.storeState.isPresent()) { this.storeState.get().getMessageStoreProvider().removeListener(this); this.storeState.get().shutdown(); this.storeState = Optional.empty(); } } public void setCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) { this.cloudConnectionStatusService = cloudConnectionStatusService; } public void unsetCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) { this.cloudConnectionStatusService = null; } public void setWatchdogService(WatchdogService watchdogService) { this.watchdogService = watchdogService; } public void unsetWatchdogService(WatchdogService watchdogService) { this.watchdogService = null; } @Override public void addDataServiceListener(DataServiceListener listener) { this.dataServiceListeners.add(listener); } @Override public void removeDataServiceListener(DataServiceListener listener) { this.dataServiceListeners.remove(listener); } @Override public void onConnectionEstablished(boolean newSession) { logger.info("Notified connected"); this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.ON); // On a new session all messages the were in-flight in the previous session // would be lost and never confirmed by the DataPublisherService. // // If the DataPublisherService is configured with Clean Start flag set to true, // then the session and connection boundaries are the same. // Otherwise, a session spans multiple connections as far as the client connects // to the same broker instance with the same client ID. // // We have two options here: // Forget them. // Unpublish them so they will be republished on the new session. // // The latter has the potential drawback that duplicates can be generated with // any QoS. // This can occur for example if the DataPublisherService is connecting with a // different client ID // or to a different broker URL resolved to the same broker instance. // // Also note that unpublished messages will be republished accordingly to their // original priority. Thus a message reordering may occur too. // Even if we artificially upgraded the priority of unpublished messages to -1 // so to // republish them first, their relative order would not necessarily match the // order // in the DataPublisherService persistence. if (newSession) { unpublishOrDropInFlightMessages(this.dataServiceOptions.isPublishInFlightMessages()); } // Notify the listeners this.dataServiceListeners.onConnectionEstablished(); signalPublisher(); } private void unpublishOrDropInFlightMessages(boolean publishInFlightMessages) { if (publishInFlightMessages && this.storeState.isPresent()) { logger.info("New session established. Unpublishing all in-flight messages. Disregarding the QoS level, " + "this may cause duplicate messages."); try { this.storeState.get().getOrOpenMessageStore().unpublishAllInFlighMessages(); this.inFlightMsgIds.clear(); } catch (KuraStoreException e) { logger.error("Failed to unpublish in-flight messages", e); DataServiceImpl.this.disconnectDataTransportAndLog(e); } } else if (this.storeState.isPresent()) { logger.info("New session established. Dropping all in-flight messages."); try { this.storeState.get().getOrOpenMessageStore().dropAllInFlightMessages(); this.inFlightMsgIds.clear(); } catch (KuraStoreException e) { logger.error("Failed to drop in-flight messages", e); DataServiceImpl.this.disconnectDataTransportAndLog(e); } } } @Override public void onDisconnecting() { logger.info("Notified disconnecting"); // Notify the listeners this.dataServiceListeners.onDisconnecting(); } @Override public void onDisconnected() { logger.info("Notified disconnected"); this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF); // Notify the listeners this.dataServiceListeners.onDisconnected(); } @Override public void onConfigurationUpdating(boolean wasConnected) { logger.info("Notified DataTransportService configuration updating..."); this.dataTransportService.disconnect(0); } @Override public void onConfigurationUpdated(boolean wasConnected) { logger.info("Notified DataTransportService configuration updated."); shutdownAutoConnectStrategy(); createAutoConnectStrategy(); if (!this.autoConnectStrategy.isPresent() && wasConnected) { try { connect(); } catch (KuraConnectException e) { logger.error("Error during re-connect after configuration update.", e); } } } @Override public void onConnectionLost(Throwable cause) { logger.info("connectionLost"); // Notify the listeners this.dataServiceListeners.onConnectionLost(cause); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { logger.debug("Message arrived on topic: {}", topic); // Notify the listeners this.dataServiceListeners.onMessageArrived(topic, payload, qos, retained); signalPublisher(); } @Override // It's very important that the publishInternal and messageConfirmed methods are // synchronized public synchronized void onMessageConfirmed(DataTransportToken token) { logger.debug("Confirmed message with MQTT message ID: {} on session ID: {}", token.getMessageId(), token.getSessionId()); Integer messageId = this.inFlightMsgIds.remove(token); if (messageId == null) { logger.info( "Confirmed message published with MQTT message ID: {} not tracked in the map of in-flight messages", token.getMessageId()); } else { Optional confirmedMessage = Optional.empty(); try { logger.info("Confirmed message ID: {} to store", messageId); if (this.storeState.isPresent()) { this.storeState.get().getOrOpenMessageStore().markAsConfirmed(messageId); confirmedMessage = this.storeState.get().getOrOpenMessageStore().get(messageId); } } catch (KuraStoreException e) { logger.error("Cannot confirm message to store", e); disconnectDataTransportAndLog(e); } // Notify the listeners if (confirmedMessage.isPresent()) { String topic = confirmedMessage.get().getTopic(); this.dataServiceListeners.onMessageConfirmed(messageId, topic); } else { logger.error("Confirmed Message with ID {} could not be loaded from the DataStore.", messageId); } } if (this.inFlightMsgIds.size() < this.dataServiceOptions.getMaxInFlightMessages()) { handleInFlightDecongestion(); } signalPublisher(); } private void disconnectDataTransportAndLog(Throwable e) { if (e instanceof KuraStoreCapacityReachedException) { return; } if (this.disconnectionGuard.compareAndSet(false, true)) { logger.error("Disconnecting the DataTransportService, cause: {}", e.getMessage()); this.disconnect(); this.disconnectionGuard.set(false); } } @Override public void connect() throws KuraConnectException { shutdownAutoConnectStrategy(); if (!this.storeState.isPresent()) { throw new KuraConnectException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); } try { this.storeState.get().getOrOpenMessageStore(); } catch (KuraStoreException e) { throw new KuraConnectException(e, MESSAGE_STORE_NOT_CONNECTED_MESSAGE); } if (!this.dataTransportService.isConnected()) { this.dataTransportService.connect(); } } @Override public boolean isConnected() { return this.dataTransportService.isConnected(); } @Override public boolean isAutoConnectEnabled() { return this.dataServiceOptions.isAutoConnect(); } @Override public int getRetryInterval() { return this.dataServiceOptions.getConnectDelay(); } @Override public void disconnect(long quiesceTimeout) { shutdownAutoConnectStrategy(); this.dataTransportService.disconnect(quiesceTimeout); } @Override public void subscribe(String topic, int qos) throws KuraException { this.dataTransportService.subscribe(topic, qos); } @Override public void unsubscribe(String topic) throws KuraException { this.dataTransportService.unsubscribe(topic); } @Override public int publish(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException { if (priority < 0) { throw new IllegalArgumentException("Priority cannot be negative"); } if (payload != null && (long) payload.length > this.dataServiceOptions.getMaximumPayloadSizeBytes()) { throw new KuraStoreException("Payload size exceeds configured limit"); } if (this.autoConnectStrategy.isPresent()) { this.autoConnectStrategy.get().onPublishRequested(topic, payload, qos, retain, priority); } if (this.storeState.isPresent()) { try { logger.info("Storing message on topic: {}, priority: {}", topic, priority); final MessageStore currentStore = this.storeState.get().getOrOpenMessageStore(); final int messageId; synchronized (currentStore) { // Priority 0 are used for life-cycle messages like birth and death // certificates. // Priority 1 are used for remove management by Cloudlet applications. // For those messages, bypass the maximum message count check of the DB cache. // We want to publish those message even if the DB is full, so allow their // storage. if (priority != 0 && priority != 1) { int count = currentStore.getMessageCount(); logger.debug("Store message count: {}", count); if (count >= this.dataServiceOptions.getStoreCapacity()) { logger.error("Store capacity exceeded"); throw new KuraStoreCapacityReachedException("Store capacity exceeded"); } } messageId = currentStore.store(topic, payload, qos, retain, priority); logger.info("Stored message on topic: {}, priority: {}", topic, priority); } signalPublisher(); return messageId; } catch (KuraStoreException e) { disconnectDataTransportAndLog(e); throw e; } } else { KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_PRESENT_MESSAGE); disconnectDataTransportAndLog(e); throw e; } } @Override public List getUnpublishedMessageIds(String topicRegex) throws KuraStoreException { if (this.storeState.isPresent()) { List messages = this.storeState.get().getOrOpenMessageStore().getUnpublishedMessages(); return buildMessageIds(messages, topicRegex); } else { KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); disconnectDataTransportAndLog(e); throw e; } } @Override public List getInFlightMessageIds(String topicRegex) throws KuraStoreException { if (this.storeState.isPresent()) { List messages = this.storeState.get().getOrOpenMessageStore().getInFlightMessages(); return buildMessageIds(messages, topicRegex); } else { KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); disconnectDataTransportAndLog(e); throw e; } } @Override public List getDroppedInFlightMessageIds(String topicRegex) throws KuraStoreException { if (this.storeState.isPresent()) { List messages = this.storeState.get().getOrOpenMessageStore().getDroppedMessages(); return buildMessageIds(messages, topicRegex); } else { KuraStoreException e = new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); disconnectDataTransportAndLog(e); throw e; } } private void signalPublisher() { this.lock.lock(); this.notifyPending = true; this.lockCondition.signal(); this.lock.unlock(); } private void createAutoConnectStrategy() { if (!this.dataServiceOptions.isAutoConnect()) { return; } final Optional currentStrategy = this.autoConnectStrategy; if (currentStrategy.isPresent()) { return; } final Optional schedule = this.dataServiceOptions.getConnectionScheduleExpression(); final AutoConnectStrategy strategy; if (!this.dataServiceOptions.isConnectionScheduleEnabled() || !schedule.isPresent()) { strategy = new AlwaysConnectedStrategy(this); } else { strategy = new ScheduleStrategy(schedule.get(), this.dataServiceOptions, this); } this.autoConnectStrategy = Optional.of(strategy); this.dataServiceListeners.prepend(strategy); } private void shutdownAutoConnectStrategy() { final Optional currentStrategy = this.autoConnectStrategy; if (currentStrategy.isPresent()) { currentStrategy.get().shutdown(); this.dataServiceListeners.remove(currentStrategy.get()); this.autoConnectStrategy = Optional.empty(); } } private void startConnectionMonitorTask() { if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) { logger.info("Reconnect task already running"); } // // Establish a reconnect Thread based on the reconnect interval boolean autoConnect = this.dataServiceOptions.isAutoConnect(); int reconnectInterval = this.dataServiceOptions.getConnectDelay(); if (autoConnect) { if (this.dataServiceOptions.isConnectionRecoveryEnabled()) { this.watchdogService.registerCriticalComponent(this); this.watchdogService.checkin(this); this.connectionAttempts = new AtomicInteger(0); } // Change notification status to slow blinking when connection is expected to // happen in the future this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.SLOW_BLINKING); // add a delay on the reconnect int maxDelay = reconnectInterval / 5; maxDelay = maxDelay > 0 ? maxDelay : 1; int initialDelay = Math.max(this.random.nextInt(maxDelay), RECONNECTION_MIN_DELAY); logger.info("Starting reconnect task with initial delay {}", initialDelay); this.connectionMonitorFuture = this.connectionMonitorExecutor.scheduleAtFixedRate(new ReconnectTask(), initialDelay, reconnectInterval, TimeUnit.SECONDS); } else { // Change notification status to off. Connection is not expected to happen in // the future this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF); unregisterAsCriticalComponent(); } } private void createThrottle() { if (this.dataServiceOptions.isRateLimitEnabled()) { int publishRate = this.dataServiceOptions.getRateLimitAverageRate(); int burstLength = this.dataServiceOptions.getRateLimitBurstSize(); long publishPeriod = this.dataServiceOptions.getRateLimitTimeUnit() / publishRate; logger.info("Get Throttle with burst length {} and send a message every {} nanoseconds", burstLength, publishPeriod); this.throttle = new TokenBucket(burstLength, publishPeriod); } } private void stopConnectionMonitorTask() { if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) { logger.info("Reconnect task running. Stopping it"); this.connectionMonitorFuture.cancel(true); } unregisterAsCriticalComponent(); } private void unregisterAsCriticalComponent() { this.watchdogService.unregisterCriticalComponent(this); } @Override public void disconnect() { long millis = this.dataServiceOptions.getDisconnectDelay() * 1000L; this.dataTransportService.disconnect(millis); } private void submitPublishingWork() { this.publisherEnabled.set(true); this.publisherExecutor.execute(new PublishManager()); } private List buildMessageIds(List messages, String topicRegex) { Pattern topicPattern = Pattern.compile(topicRegex); List ids = new ArrayList<>(); if (messages != null) { for (StoredMessage message : messages) { String topic = message.getTopic(); if (topicPattern.matcher(topic).matches()) { ids.add(message.getId()); } } } return ids; } private void handleInFlightDecongestion() { if (this.congestionFuture != null && !this.congestionFuture.isDone()) { this.congestionFuture.cancel(true); } } @Override public int getNotificationPriority() { return CloudConnectionStatusService.PRIORITY_LOW; } @Override public CloudConnectionStatusEnum getNotificationStatus() { return this.notificationStatus; } @Override public void setNotificationStatus(CloudConnectionStatusEnum status) { this.notificationStatus = status; } private final class ReconnectTask implements Runnable { @Override public void run() { Thread.currentThread().setName( "DataServiceImpl:ReconnectTask:" + DataServiceImpl.this.dataServiceOptions.getKuraServicePid()); boolean connected = false; try { if (!DataServiceImpl.this.storeState.isPresent()) { logger.warn(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); } DataServiceImpl.this.storeState.get().getOrOpenMessageStore(); logger.info("Connecting..."); if (DataServiceImpl.this.dataTransportService.isConnected()) { logger.info("Already connected. Reconnect task will be terminated."); } else { DataServiceImpl.this.dataTransportService.connect(); logger.info("Connected. Reconnect task will be terminated."); } connected = true; } catch (KuraConnectException | KuraStoreException e) { logger.warn("Connection attempt failed with exception {}", e.getClass().getSimpleName(), e); if (DataServiceImpl.this.dataServiceOptions.isConnectionRecoveryEnabled()) { if (isAuthenticationException(e) || e instanceof KuraStoreException || DataServiceImpl.this.connectionAttempts .getAndIncrement() < DataServiceImpl.this.dataServiceOptions .getRecoveryMaximumAllowedFailures()) { logger.info("Checkin done."); DataServiceImpl.this.watchdogService.checkin(DataServiceImpl.this); } else { logger.info("Maximum number of connection attempts reached. Requested reboot..."); } } } finally { if (connected) { unregisterAsCriticalComponent(); // Throwing an exception will suppress subsequent executions of this periodic // task. throw new RuntimeException("Connected. Reconnect task will be terminated."); } } } private boolean isAuthenticationException(KuraException e) { boolean authenticationException = false; if (e.getCause() instanceof MqttException) { MqttException mqttException = (MqttException) e.getCause(); if (mqttException.getReasonCode() == MqttException.REASON_CODE_FAILED_AUTHENTICATION || mqttException.getReasonCode() == MqttException.REASON_CODE_INVALID_CLIENT_ID || mqttException.getReasonCode() == MqttException.REASON_CODE_NOT_AUTHORIZED) { logger.info("Authentication exception encountered."); authenticationException = true; } } return authenticationException; } } private final class PublishManager implements Runnable { @Override public void run() { Thread.currentThread().setName("DataServiceImpl:Submit"); while (DataServiceImpl.this.publisherEnabled.get()) { long sleepingTime = -1; boolean messagePublished = false; if (DataServiceImpl.this.dataTransportService.isConnected()) { try { if (DataServiceImpl.this.storeState.isPresent()) { final Optional message = DataServiceImpl.this.storeState.get() .getOrOpenMessageStore().getNextMessage(); if (message.isPresent()) { checkInFlightMessages(message.get()); if (DataServiceImpl.this.dataServiceOptions.isRateLimitEnabled() && message.get().getPriority() >= 5) { messagePublished = publishMessageTokenBucket(message.get()); sleepingTime = DataServiceImpl.this.throttle.getTokenWaitTime(); } else { publishMessageUnbound(message.get()); messagePublished = true; } } } } catch (KuraNotConnectedException e) { logger.info("DataPublisherService is not connected"); } catch (KuraTooManyInflightMessagesException e) { logger.info("Too many in-flight messages"); handleInFlightCongestion(); } catch (Exception e) { logger.error("Probably an unrecoverable exception", e); } } else { logger.info("DataPublisherService not connected"); } if (!messagePublished) { suspendPublisher(sleepingTime, TimeUnit.NANOSECONDS); } } logger.debug("Exited publisher loop."); } private void checkInFlightMessages(StoredMessage message) throws KuraTooManyInflightMessagesException { if (message.getQos() > 0 && DataServiceImpl.this.inFlightMsgIds .size() >= DataServiceImpl.this.dataServiceOptions.getMaxInFlightMessages()) { logger.warn("The configured maximum number of in-flight messages has been reached"); throw new KuraTooManyInflightMessagesException("Too many in-flight messages"); } } private void suspendPublisher(long timeout, TimeUnit timeUnit) { if (!DataServiceImpl.this.publisherEnabled.get()) { return; } try { DataServiceImpl.this.lock.lock(); if (!DataServiceImpl.this.notifyPending) { if (timeout == -1) { logger.debug("Suspending publishing thread indefinitely"); DataServiceImpl.this.lockCondition.await(); } else { logger.debug("Suspending publishing thread for {} nanoseconds", timeout); DataServiceImpl.this.lockCondition.await(timeout, timeUnit); } } DataServiceImpl.this.notifyPending = false; } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { DataServiceImpl.this.lock.unlock(); } } private void publishMessageUnbound(StoredMessage message) throws KuraException { publishInternal(message); // Notify the listeners DataServiceImpl.this.dataServiceListeners.onMessagePublished(message.getId(), message.getTopic()); } private boolean publishMessageTokenBucket(StoredMessage message) throws KuraException { boolean tokenAvailable = DataServiceImpl.this.throttle.getToken(); if (tokenAvailable) { publishMessageUnbound(message); return true; } return false; } private void handleInFlightCongestion() { int timeout = DataServiceImpl.this.dataServiceOptions.getInFlightMessagesCongestionTimeout(); // Do not schedule more that one task at a time if (timeout != 0 && (DataServiceImpl.this.congestionFuture == null || DataServiceImpl.this.congestionFuture.isDone())) { logger.warn("In-flight message congestion timeout started"); DataServiceImpl.this.congestionFuture = DataServiceImpl.this.congestionExecutor.schedule(() -> { Thread.currentThread().setName("DataServiceImpl:InFlightCongestion"); logger.warn("In-flight message congestion timeout elapsed. Disconnecting and reconnecting again"); disconnect(); startConnectionMonitorTask(); }, timeout, TimeUnit.SECONDS); } } // It's very important that the publishInternal and messageConfirmed methods are // synchronized private synchronized void publishInternal(StoredMessage message) throws KuraException { String topic = message.getTopic(); byte[] payload = message.getPayload(); int qos = message.getQos(); boolean retain = message.isRetain(); int msgId = message.getId(); logger.debug("Publishing message with ID: {} on topic: {}, priority: {}", msgId, topic, message.getPriority()); DataTransportToken token = DataServiceImpl.this.dataTransportService.publish(topic, payload, qos, retain); if (DataServiceImpl.this.storeState.isPresent()) { try { if (token == null) { DataServiceImpl.this.storeState.get().getOrOpenMessageStore().markAsPublished(msgId); logger.debug("Published message with ID: {}", msgId); } else { // Check if the token is already tracked in the map (in which case we are in // trouble) Integer trackedMsgId = DataServiceImpl.this.inFlightMsgIds.get(token); if (trackedMsgId != null) { logger.error("Token already tracked: {} - {}", token.getSessionId(), token.getMessageId()); } DataServiceImpl.this.inFlightMsgIds.put(token, msgId); DataServiceImpl.this.storeState.get().getOrOpenMessageStore().markAsPublished(msgId, token); logger.debug("Published message with ID: {} and MQTT message ID: {}", msgId, token.getMessageId()); } } catch (KuraStoreException e) { DataServiceImpl.this.disconnectDataTransportAndLog(e); } } else { throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); } } } @Override public String getCriticalComponentName() { return "DataServiceImpl"; } @Override public int getCriticalComponentTimeout() { return this.dataServiceOptions.getCriticalComponentTimeout(); } public Map getConnectionInfo() { Map result = new HashMap<>(); result.put("Broker URL", this.dataTransportService.getBrokerUrl()); result.put("Account", this.dataTransportService.getAccountName()); result.put("Username", this.dataTransportService.getUsername()); result.put("Client ID", this.dataTransportService.getClientId()); return result; } @Override public void startConnectionTask() { if (!this.dataTransportService.isConnected()) { startConnectionMonitorTask(); } } @Override public void stopConnectionTask() { stopConnectionMonitorTask(); } @Override public boolean hasInFlightMessages() { return !this.inFlightMsgIds.isEmpty(); } @Override public Optional getNextMessage() { Optional message = Optional.empty(); try { if (DataServiceImpl.this.storeState.isPresent()) { message = DataServiceImpl.this.storeState.get().getOrOpenMessageStore().getNextMessage(); } else { throw new KuraStoreException(MESSAGE_STORE_NOT_CONNECTED_MESSAGE); } } catch (Exception e) { DataServiceImpl.this.disconnectDataTransportAndLog(e); logger.error("Probably an unrecoverable exception", e); } return message; } @Override public void connected() { logger.info("Message store with PID {} connected.", this.dataServiceOptions.getDbServiceInstancePid()); if (this.connectionMonitorFuture != null && !this.connectionMonitorFuture.isDone()) { stopConnectionTask(); startConnectionTask(); } } @Override public void disconnected() { logger.info("Message store with PID {} disconnected.", this.dataServiceOptions.getDbServiceInstancePid()); if (this.storeState.isPresent()) { this.storeState.get().shutdown(); } if (this.dataTransportService.isConnected()) { this.disconnect(); logger.info("Message store disconnected. Trying to shutdown the DataTransportService."); } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceListenerS.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.kura.data.listener.DataServiceListener; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * The following represents an exception to Semantic Versioning conventions. * Though the class implements the org.eclipse.kura.data.listener.DataServiceListener API, * it is actually an API consumer (it calls into the API implementors). */ class DataServiceListenerS implements DataServiceListener { private static final Logger logger = LoggerFactory.getLogger(DataServiceListenerS.class); private static final String DATA_SERVICE_LISTENER_REFERENCE = "DataServiceListener"; private final ComponentContext ctx; private final List listeners; public DataServiceListenerS(ComponentContext ctx) { this.ctx = ctx; // thread-safe list implementation this.listeners = new CopyOnWriteArrayList<>(); } @Override public void onConnectionEstablished() { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onConnectionEstablished(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConnectionEstablished"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onConnectionEstablished(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConnectionEstablished"); } } @Override public void onDisconnecting() { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onDisconnecting(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onDisconnecting"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onDisconnecting(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onDisconnecting"); } } @Override public void onDisconnected() { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onDisconnected(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onDisconnected"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onDisconnected(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onDisconnected"); } } @Override public void onConnectionLost(Throwable cause) { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onConnectionLost(cause); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConnectionLost"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onConnectionLost(cause); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConnectionLost"); } } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onMessageArrived(topic, payload, qos, retained); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onMessageArrived"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onMessageArrived(topic, payload, qos, retained); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onMessageArrived"); } } @Override public void onMessagePublished(int messageId, String topic) { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onMessagePublished(messageId, topic); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onMessagePublished"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onMessagePublished(messageId, topic); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onMessagePublished"); } } @Override public void onMessageConfirmed(int messageId, String topic) { Object[] services = this.ctx.locateServices(DATA_SERVICE_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataServiceListener) service).onMessageConfirmed(messageId, topic); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onMessageConfirmed"); } if (!this.listeners.isEmpty()) { for (DataServiceListener listener : this.listeners) { try { listener.onMessageConfirmed(messageId, topic); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onMessageConfirmed"); } } public void prepend(DataServiceListener listener) { this.listeners.add(0, listener); } public void add(DataServiceListener listener) { this.listeners.add(listener); } public void remove(DataServiceListener listener) { this.listeners.remove(listener); } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.concurrent.TimeUnit; import org.eclipse.kura.configuration.ConfigurationService; import org.quartz.CronExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.util.Objects.requireNonNull; public class DataServiceOptions { private static final Logger logger = LoggerFactory.getLogger(DataServiceOptions.class); private static final String AUTOCONNECT_PROP_NAME = "connect.auto-on-startup"; private static final String CONNECT_DELAY_PROP_NAME = "connect.retry-interval"; private static final String DISCONNECT_DELAY_PROP_NAME = "disconnect.quiesce-timeout"; private static final String STORE_DB_SERVICE_INSTANCE_PROP_NAME = "store.db.service.pid"; private static final String STORE_HOUSEKEEPER_INTERVAL_PROP_NAME = "store.housekeeper-interval"; private static final String STORE_PURGE_AGE_PROP_NAME = "store.purge-age"; private static final String STORE_CAPACITY_PROP_NAME = "store.capacity"; private static final String REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME = "in-flight-messages.republish-on-new-session"; private static final String MAX_IN_FLIGHT_MSGS_PROP_NAME = "in-flight-messages.max-number"; private static final String IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME = "in-flight-messages.congestion-timeout"; private static final String RATE_LIMIT_ENABLE_PROP_NAME = "enable.rate.limit"; private static final String RATE_LIMIT_AVERAGE_RATE_PROP_NAME = "rate.limit.average"; private static final String RATE_LIMIT_TIME_UNIT_PROP_NAME = "rate.limit.time.unit"; private static final String RATE_LIMIT_BURST_SIZE_PROP_NAME = "rate.limit.burst.size"; private static final String RECOVERY_ENABLE_PROP_NAME = "enable.recovery.on.connection.failure"; private static final String RECOVERY_MAX_FAILURES_PROP_NAME = "connection.recovery.max.failures"; private static final String CONNECTION_SCHEDULE_ENABLED = "connection.schedule.enabled"; private static final String CONNECTION_SCHECULE_EXPRESSION = "connection.schedule.expression"; private static final String CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS = "connection.schedule.inactivity.interval.seconds"; private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE = "connection.schedule.priority.override.enable"; private static final String CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD = "connection.schedule.priority.override.threshold"; private static final String MAXIMUM_PAYLOAD_SIZE = "maximum.payload.size"; private static final boolean AUTOCONNECT_PROP_DEFAULT = false; private static final int CONNECT_DELAY_DEFAULT = 60; private static final int DISCONNECT_DELAY_DEFAULT = 10; private static final String DB_SERVICE_INSTANCE_DEFAULT = "org.eclipse.kura.db.H2DbService"; private static final int STORE_HOUSEKEEPER_INTERVAL_DEFAULT = 900; private static final int STORE_PURGE_AGE_DEFAULT = 60; private static final int STORE_CAPACITY_DEFAULT = 10000; private static final boolean REPUBLISH_IN_FLIGHT_MSGS_DEFAULT = true; private static final int MAX_IN_FLIGHT_MSGS_DEFAULT = 9; private static final int IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT = 0; private static final boolean RATE_LIMIT_ENABLE_DEFAULT = true; private static final int RATE_LIMIT_AVERAGE_RATE_DEFAULT = 1; private static final String RATE_LIMIT_TIME_UNIT_DEFAULT = "SECONDS"; private static final int RATE_LIMIT_BURST_SIZE_DEFAULT = 1; private static final boolean RECOVERY_ENABLE_DEFAULT = true; private static final int RECOVERY_MAX_FAILURES_DEFAULT = 10; private static final boolean CONNECTION_SCHEDULE_ENABLED_DEFAULT = false; private static final long CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_DEFAULT = 60; private static final boolean CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT = false; private static final int CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT = 1; private static final long MAXIMUM_PAYLOAD_SIZE_DEFAULT = 16777216; private static final int CONNECT_CRITICAL_COMPONENT_TIMEOUT_MULTIPLIER = 5000; private final Map properties; DataServiceOptions(Map properties) { requireNonNull(properties, "Required not null"); this.properties = Collections.unmodifiableMap(properties); } public int getStoreHousekeeperInterval() { return (int) this.properties.getOrDefault(STORE_HOUSEKEEPER_INTERVAL_PROP_NAME, STORE_HOUSEKEEPER_INTERVAL_DEFAULT); } public int getStorePurgeAge() { return (int) this.properties.getOrDefault(STORE_PURGE_AGE_PROP_NAME, STORE_PURGE_AGE_DEFAULT); } public int getStoreCapacity() { return (int) this.properties.getOrDefault(STORE_CAPACITY_PROP_NAME, STORE_CAPACITY_DEFAULT); } public boolean isPublishInFlightMessages() { return (boolean) this.properties.getOrDefault(REPUBLISH_IN_FLIGHT_MSGS_PROP_NAME, REPUBLISH_IN_FLIGHT_MSGS_DEFAULT); } public int getMaxInFlightMessages() { return (int) this.properties.getOrDefault(MAX_IN_FLIGHT_MSGS_PROP_NAME, MAX_IN_FLIGHT_MSGS_DEFAULT); } public int getInFlightMessagesCongestionTimeout() { return (int) this.properties.getOrDefault(IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_PROP_NAME, IN_FLIGHT_MSGS_CONGESTION_TIMEOUT_DEFAULT); } public boolean isAutoConnect() { return (boolean) this.properties.getOrDefault(AUTOCONNECT_PROP_NAME, AUTOCONNECT_PROP_DEFAULT); } public int getConnectDelay() { return (int) this.properties.getOrDefault(CONNECT_DELAY_PROP_NAME, CONNECT_DELAY_DEFAULT); } public int getDisconnectDelay() { return (int) this.properties.getOrDefault(DISCONNECT_DELAY_PROP_NAME, DISCONNECT_DELAY_DEFAULT); } public boolean isRateLimitEnabled() { return (boolean) this.properties.getOrDefault(RATE_LIMIT_ENABLE_PROP_NAME, RATE_LIMIT_ENABLE_DEFAULT); } public int getRateLimitAverageRate() { return (int) this.properties.getOrDefault(RATE_LIMIT_AVERAGE_RATE_PROP_NAME, RATE_LIMIT_AVERAGE_RATE_DEFAULT); } public int getRateLimitBurstSize() { return (int) this.properties.getOrDefault(RATE_LIMIT_BURST_SIZE_PROP_NAME, RATE_LIMIT_BURST_SIZE_DEFAULT); } public long getRateLimitTimeUnit() { String timeUnitString = (String) this.properties.getOrDefault(RATE_LIMIT_TIME_UNIT_PROP_NAME, RATE_LIMIT_TIME_UNIT_DEFAULT); TimeUnit timeUnit; if (TimeUnit.MILLISECONDS.name().equals(timeUnitString)) { timeUnit = TimeUnit.MILLISECONDS; } else if (TimeUnit.SECONDS.name().equals(timeUnitString)) { timeUnit = TimeUnit.SECONDS; } else if (TimeUnit.MINUTES.name().equals(timeUnitString)) { timeUnit = TimeUnit.MINUTES; } else if (TimeUnit.HOURS.name().equals(timeUnitString)) { timeUnit = TimeUnit.HOURS; } else if (TimeUnit.DAYS.name().equals(timeUnitString)) { timeUnit = TimeUnit.DAYS; } else { throw new IllegalArgumentException("Illegal time unit"); } return timeUnit.toNanos(1); } public String getDbServiceInstancePid() { return (String) this.properties.getOrDefault(STORE_DB_SERVICE_INSTANCE_PROP_NAME, DB_SERVICE_INSTANCE_DEFAULT); } public String getKuraServicePid() { return (String) this.properties.get(ConfigurationService.KURA_SERVICE_PID); } public boolean isConnectionRecoveryEnabled() { return (boolean) this.properties.getOrDefault(RECOVERY_ENABLE_PROP_NAME, RECOVERY_ENABLE_DEFAULT); } public int getRecoveryMaximumAllowedFailures() { return (int) this.properties.getOrDefault(RECOVERY_MAX_FAILURES_PROP_NAME, RECOVERY_MAX_FAILURES_DEFAULT); } public int getCriticalComponentTimeout() { return getConnectDelay() * CONNECT_CRITICAL_COMPONENT_TIMEOUT_MULTIPLIER; } public boolean isConnectionScheduleEnabled() { return (boolean) this.properties.getOrDefault(CONNECTION_SCHEDULE_ENABLED, CONNECTION_SCHEDULE_ENABLED_DEFAULT); } public Optional getConnectionScheduleExpression() { if (!this.isConnectionScheduleEnabled()) { return Optional.empty(); } try { return Optional.of(new CronExpression((String) this.properties.get(CONNECTION_SCHECULE_EXPRESSION))); } catch (final Exception e) { logger.warn("failed to parse connection schedule expression", e); return Optional.empty(); } } public long getConnectionScheduleDisconnectDelay() { return (long) this.properties.getOrDefault(CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS, CONNECTION_SCHEDULE_INACTIVITY_INTERVAL_SECONDS_DEFAULT); } public boolean isConnectionSchedulePriorityOverrideEnabled() { return (Boolean) this.properties.getOrDefault(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE, CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_ENABLE_DEFAULT) && isConnectionScheduleEnabled() && getConnectionScheduleExpression().isPresent(); } public int getConnectionSchedulePriorityOverridePriority() { return (Integer) this.properties.getOrDefault(CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD, CONNECTION_SCHEDULE_PRIORITY_OVERRIDE_THRESHOLD_DEFAULT); } public long getMaximumPayloadSizeBytes() { try { return (long) this.properties.getOrDefault(MAXIMUM_PAYLOAD_SIZE, MAXIMUM_PAYLOAD_SIZE_DEFAULT); } catch (final Exception e) { return MAXIMUM_PAYLOAD_SIZE_DEFAULT; } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/DataStore.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data; import java.util.List; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.db.H2DbService; /** * DataStore implementation have the responsibility of doing the bookkeeping of * the messages that are in transient in the system. A message in the system * normally flows through the following states: stored -> published -> * confirmed (or dropped). The data store should be able to store messages, track and update * their state, and perform certain queries for messages in a given state. */ public interface DataStore { public void start(H2DbService dbService, int houseKeeperInterval, int purgeAge, int capacity) throws KuraStoreException; public void update(int houseKeeperInterval, int purgeAge, int capacity); public void stop(); /** * Stores an MQTT message for deferred publication. An identifier is always * generated and returned, even for messages published with QoS = 0. The * store policy is FIFO within each priority level, 0 being the highest * priority. * * @param topic * @param payload * @param qos * @param retain * @param priority * @return * @throws KuraStoreException */ public DataMessage store(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException; /** * Acknowledges the publication of the DataMessage with the given ID * associating it to the protocol (e.g. MQTT) message ID (QoS > 0). * * @param msgId * @param publishedMsgId * @param sessionId * TODO * @throws KuraStoreException */ public void published(int msgId, int publishedMsgId, String sessionId) throws KuraStoreException; /** * Acknowledges the publication of the DataMessage with the given ID. This * is typically called for messages published with QoS = 0. * * @param msgId * @param publishedMsgId * @throws KuraStoreException */ public void published(int msgId) throws KuraStoreException; /** * Acknowledges the delivery of the DataMessage published with the given * protocol (e.g. MQTT) message ID. This method is only called for messages * published with QoS > 0. * * @param msgId * @throws KuraStoreException */ public void confirmed(int msgId) throws KuraStoreException; /** * Gets the next unpublished message. Messages with higher * priority (0 is the highest priority) are returned first. Within each * priority level the oldest unpublished message is returned first. * * @return * @throws KuraStoreException */ public DataMessage getNextMessage() throws KuraStoreException; /** * Returns a message from the DataStore by its message id. * * @param msgId * ID of the message to be loaded * @return Loaded message or null if not found. * @throws KuraStoreException */ public DataMessage get(int msgId) throws KuraStoreException; /** * Finds the list of all unpublished messages and returns them WITHOUT loading the payload. * * @return * @throws KuraStoreException */ public List allUnpublishedMessagesNoPayload() throws KuraStoreException; /** * Finds the list of all published but not yet confirmed messages and returns them WITHOUT loading the payload. * These are only messages published with QoS > 0. * Messages published with QoS = 0 do not belong to the results list. * * @return * @throws KuraStoreException */ public List allInFlightMessagesNoPayload() throws KuraStoreException; /** * Finds the list of all published messages that will not be confirmed and returns them WITHOUT loading the payload. * These are only messages published with QoS > 0. * Messages published with QoS = 0 do not belong to the results list. * * @return */ public List allDroppedInFlightMessagesNoPayload() throws KuraStoreException; /** * Marks all in-flight messages as unpublished. * * @throws KuraStoreException */ public void unpublishAllInFlighMessages() throws KuraStoreException; /** * Drops all in-flight messages. * * @throws KuraStoreException */ public void dropAllInFlightMessages() throws KuraStoreException; /** * Deletes stale messages. * These are either published messages with QoS = 0 or confirmed messages with QoS > 0, whose age exceeds the * argument. * * @param purgeAge * @throws KuraStoreException */ public void deleteStaleMessages(int purgeAge) throws KuraStoreException; /** * Checks and attempts to repair the store. * * @throws KuraStoreException */ public void repair() throws KuraStoreException; } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/ScheduleStrategy.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.data; import java.util.Date; import java.util.Optional; import java.util.OptionalLong; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import java.util.function.UnaryOperator; import org.eclipse.kura.message.store.StoredMessage; import org.quartz.CronExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ScheduleStrategy implements AutoConnectStrategy { private static final Logger logger = LoggerFactory.getLogger(ScheduleStrategy.class); private final ScheduledExecutorService executor; private final CronExpression expression; private final long disconnectTimeoutMs; private final ConnectionManager connectionManager; private final Supplier currentTimeProvider; private State state; private Optional> timeout = Optional.empty(); private DataServiceOptions dataServiceOptions; public ScheduleStrategy(final CronExpression expression, DataServiceOptions dataServiceOptions, final ConnectionManager connectionManager) { this(expression, dataServiceOptions.getConnectionScheduleDisconnectDelay() * 1000, connectionManager, Executors.newSingleThreadScheduledExecutor(), Date::new, dataServiceOptions); } public ScheduleStrategy(final CronExpression expression, final long disconnectTimeoutMs, final ConnectionManager connectionManager, final ScheduledExecutorService executor, final Supplier currentTimeProvider, DataServiceOptions dataServiceOptions) { this.expression = expression; this.disconnectTimeoutMs = disconnectTimeoutMs; this.connectionManager = connectionManager; this.state = new AwaitConnectTime(); this.executor = executor; this.currentTimeProvider = currentTimeProvider; this.dataServiceOptions = dataServiceOptions; updateState(State::onEnterState); executor.scheduleWithFixedDelay(new TimeShiftDetector(60000), 0, 1, TimeUnit.MINUTES); } private interface State { public default State onEnterState() { return this; } public default State onConnectionEstablished() { return this; } public default State onMessageEvent() { return this; } public default State onConnectionLost() { return this; } public default State onTimeout() { return this; } public default State onPublish(String topic, byte[] payload, int qos, boolean retain, int priority) { return this; } } private class AwaitConnectTime implements State { @Override public State onEnterState() { Optional dm = connectionManager.getNextMessage(); if (dm.isPresent() && dm.get().getPriority() <= dataServiceOptions.getConnectionSchedulePriorityOverridePriority()) { logger.info( "Priority message sent while disconnecting. Initiating Connection to send message with a high priority."); return new AwaitConnect(); } final Date now = currentTimeProvider.get(); final Date nextTick = expression.getNextValidTimeAfter(now); final long delay = Math.max(1, nextTick.getTime() - now.getTime()); logger.info("Connection scheduled at {} in {} ms", nextTick, delay); rescheduleTimeout(delay); return this; } @Override public State onTimeout() { return new AwaitConnect(); } @Override public State onPublish(String topic, byte[] payload, int qos, boolean retain, int priority) { if (dataServiceOptions.isConnectionSchedulePriorityOverrideEnabled() && priority <= dataServiceOptions.getConnectionSchedulePriorityOverridePriority() && !connectionManager.isConnected()) { logger.info("Initiating Connection to send message with a high priority."); return new AwaitConnect(); } return this; } } private class AwaitConnect implements State { @Override public State onEnterState() { if (connectionManager.isConnected()) { return new AwaitDisconnectTime(); } else { connectionManager.startConnectionTask(); return this; } } @Override public State onConnectionLost() { connectionManager.startConnectionTask(); return this; } @Override public State onConnectionEstablished() { return new AwaitDisconnectTime(); } } private class AwaitDisconnectTime implements State { @Override public State onEnterState() { return onMessageEvent(); } @Override public State onConnectionLost() { return new AwaitConnect(); } @Override public State onMessageEvent() { rescheduleTimeout(disconnectTimeoutMs); return this; } @Override public State onTimeout() { if (connectionManager.hasInFlightMessages()) { return this; } else { return new AwaitDisconnect(); } } } private class AwaitDisconnect implements State { @Override public State onEnterState() { connectionManager.stopConnectionTask(); connectionManager.disconnect(); return this; } @Override public State onConnectionLost() { return new AwaitConnectTime(); } @Override public State onMessageEvent() { return this; } } private void rescheduleTimeout(final long timeoutMs) { cancelTimeout(); this.timeout = Optional.of(executor.schedule(() -> updateState(State::onTimeout), timeoutMs, TimeUnit.MILLISECONDS)); } private void cancelTimeout() { final Optional> currentFuture = this.timeout; if (currentFuture.isPresent()) { currentFuture.get().cancel(false); } } private void updateState(final UnaryOperator transition) { executor.execute(() -> updateStateInternal(transition)); } private void updateStateInternal(final UnaryOperator transitionFunction) { final Optional> currentFuture = this.timeout; final State nextState = transitionFunction.apply(this.state); if (nextState != this.state) { logger.info("State change: {} -> {}", state.getClass().getSimpleName(), nextState.getClass().getSimpleName()); currentFuture.ifPresent(c -> c.cancel(false)); this.state = nextState; updateStateInternal(State::onEnterState); } } private class TimeShiftDetector implements Runnable { private OptionalLong previousTimestamp = OptionalLong.empty(); private final long expectedDelay; public TimeShiftDetector(final long expectedTickRate) { this.expectedDelay = expectedTickRate; } public void run() { final long now = System.currentTimeMillis(); final OptionalLong previous = this.previousTimestamp; if (!previous.isPresent()) { this.previousTimestamp = OptionalLong.of(now); return; } if (now < previous.getAsLong() || Math.abs((now - previous.getAsLong()) - expectedDelay) > 60000) { logger.warn("Time shift detected, reinitializing connection schedule"); updateState(c -> new AwaitConnectTime()); } this.previousTimestamp = OptionalLong.of(now); } } @Override public void shutdown() { executor.execute(() -> { cancelTimeout(); executor.shutdown(); }); try { executor.awaitTermination(30, TimeUnit.SECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.warn("Interrupted while waiting for executor shutdown"); } } @Override public void onConnectionEstablished() { updateState(State::onConnectionEstablished); } @Override public void onDisconnecting() { // no need } @Override public void onDisconnected() { updateState(State::onConnectionLost); } @Override public void onConnectionLost(Throwable cause) { updateState(State::onConnectionLost); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { // no need } @Override public void onMessagePublished(int messageId, String topic) { updateState(State::onMessageEvent); } @Override public void onMessageConfirmed(int messageId, String topic) { updateState(State::onMessageEvent); } @Override public void onPublishRequested(String topic, byte[] payload, int qos, boolean retain, int priority) { this.updateState(c -> this.state.onPublish(topic, payload, qos, retain, priority)); } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/store/HouseKeeperTask.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data.store; import org.eclipse.kura.KuraStoreException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Housekeeper Task which periodically purges confirmed messages from the local * database. * It also contains the total number of messages in the system to a given cap. */ public class HouseKeeperTask implements Runnable { private static final Logger logger = LoggerFactory.getLogger(HouseKeeperTask.class); private final int purgeAge; private final MessageStoreState store; public HouseKeeperTask(MessageStoreState store, int purgeAge) { this.purgeAge = purgeAge; this.store = store; } @Override public void run() { try { Thread.currentThread().setName(getClass().getSimpleName()); logger.info("HouseKeeperTask started."); // // delete all confirmed messages logger.info("HouseKeeperTask: Delete confirmed messages..."); this.store.getOrOpenMessageStore().deleteStaleMessages(this.purgeAge); logger.info("HouseKeeperTask ended."); } catch (KuraStoreException me) { // do not throw the exception as that will stop future executions logger.warn("HouseCleaningTask exception", me); } catch (Throwable t) { // do not throw the exception as that will stop future executions if (t instanceof InterruptedException) { logger.info("HouseCleaningTask stopped"); } else { logger.warn("HouseCleaningTask exception", t); } } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/store/MessageStoreState.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.data.store; import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.core.data.DataServiceOptions; import org.eclipse.kura.message.store.provider.MessageStore; import org.eclipse.kura.message.store.provider.MessageStoreProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageStoreState { private static final Logger logger = LoggerFactory.getLogger(MessageStoreState.class); private final MessageStoreProvider messageStoreProvider; private DataServiceOptions options; private Optional messageStore = Optional.empty(); private Optional houseKeeperExecutor = Optional.empty(); public MessageStoreState(final MessageStoreProvider messageStoreProvider, final DataServiceOptions options) { this.messageStoreProvider = messageStoreProvider; update(options); } public synchronized void update(final DataServiceOptions dataServiceOptions) { this.options = dataServiceOptions; shutdown(); if (!this.houseKeeperExecutor.isPresent()) { this.houseKeeperExecutor = Optional.of(Executors.newSingleThreadScheduledExecutor()); this.houseKeeperExecutor.get().scheduleWithFixedDelay( new HouseKeeperTask(this, dataServiceOptions.getStorePurgeAge()), 1, // start in one second dataServiceOptions.getStoreHousekeeperInterval(), // repeat every retryInterval until we stopped. TimeUnit.SECONDS); } } public MessageStoreProvider getMessageStoreProvider() { return messageStoreProvider; } public synchronized MessageStore getOrOpenMessageStore() throws KuraStoreException { if (this.messageStore.isPresent()) { return this.messageStore.get(); } return this.openMessageStore(); } public synchronized MessageStore openMessageStore() throws KuraStoreException { final MessageStore result = this.messageStoreProvider.openMessageStore(this.options.getKuraServicePid()); this.messageStore = Optional.of(result); return result; } public synchronized void shutdown() { if (this.houseKeeperExecutor.isPresent()) { this.houseKeeperExecutor.get().shutdown(); try { this.houseKeeperExecutor.get().awaitTermination(30, TimeUnit.SECONDS); } catch (final InterruptedException e) { logger.warn("Interrupted while waiting for housekeeper task shutdown", e); Thread.currentThread().interrupt(); } this.houseKeeperExecutor = Optional.empty(); } if (this.messageStore.isPresent()) { this.messageStore.get().close(); this.messageStore = Optional.empty(); } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/DataTransportListenerS.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data.transport.mqtt; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.kura.data.DataTransportToken; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * The following represents an exception to Semantic Versioning conventions. * Though the class implements the org.eclipse.kura.data.transport.listener.DataTransportListener API, * it is actually an API consumer (it calls into the API implementors). */ class DataTransportListenerS implements DataTransportListener { private static final Logger logger = LoggerFactory.getLogger(DataTransportListenerS.class); private static final String DATA_TRANSPORT_LISTENER_REFERENCE = "DataTransportListener"; private final ComponentContext ctx; private final List listeners; public DataTransportListenerS(ComponentContext ctx) { this.ctx = ctx; this.listeners = new CopyOnWriteArrayList<>(); } @Override public void onConnectionEstablished(boolean newSession) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onConnectionEstablished(newSession); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConnectionEstablished"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onConnectionEstablished(newSession); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConnectionEstablished"); } } @Override public void onDisconnecting() { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onDisconnecting(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onDisconnecting"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onDisconnecting(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onDisconnecting"); } } @Override public void onDisconnected() { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onDisconnected(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onDisconnected"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onDisconnected(); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onDisconnected"); } } @Override public void onConfigurationUpdating(boolean wasConnected) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onConfigurationUpdating(wasConnected); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConfigurationUpdating"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onConfigurationUpdating(wasConnected); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConfigurationUpdating"); } } @Override public void onConfigurationUpdated(boolean wasConnected) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onConfigurationUpdated(wasConnected); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConfigurationUpdated"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onConfigurationUpdated(wasConnected); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConfigurationUpdated"); } } @Override public void onConnectionLost(Throwable cause) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onConnectionLost(cause); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onConnectionLost"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onConnectionLost(cause); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onConnectionLost"); } } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onMessageArrived(topic, payload, qos, retained); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onMessageArrived"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onMessageArrived(topic, payload, qos, retained); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onMessageArrived"); } } @Override public void onMessageConfirmed(DataTransportToken token) { Object[] services = this.ctx.locateServices(DATA_TRANSPORT_LISTENER_REFERENCE); if (services != null) { for (Object service : services) { try { ((org.eclipse.kura.data.DataTransportListener) service).onMessageConfirmed(token); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.debug("No registered listener services. Ignoring onMessageConfirmed"); } if (!this.listeners.isEmpty()) { for (DataTransportListener listener : this.listeners) { try { listener.onMessageConfirmed(token); } catch (Throwable t) { logger.warn("Unexpected Throwable", t); } } } else { logger.warn("No registered listeners. Ignoring onMessageConfirmed"); } } public void add(DataTransportListener listener) { this.listeners.add(listener); } public void remove(DataTransportListener listener) { this.listeners.remove(listener); } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/MqttClientConfiguration.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data.transport.mqtt; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; public class MqttClientConfiguration { private final String brokerUrl; private final String clientId; private final PersistenceType persistenceType; private final MqttConnectOptions connectOptions; public enum PersistenceType { FILE, MEMORY } public MqttClientConfiguration(String brokerUrl, String clientId, PersistenceType persistenceType, MqttConnectOptions connectOptions) { super(); this.brokerUrl = brokerUrl; this.clientId = clientId; this.persistenceType = persistenceType; this.connectOptions = connectOptions; } public String getBrokerUrl() { return this.brokerUrl; } public String getClientId() { return this.clientId; } public PersistenceType getPersistenceType() { return this.persistenceType; } public MqttConnectOptions getConnectOptions() { return this.connectOptions; } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/transport/mqtt/MqttDataTransport.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.data.transport.mqtt; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.net.ssl.SSLSocketFactory; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.KuraTimeoutException; import org.eclipse.kura.KuraTooManyInflightMessagesException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.core.data.transport.mqtt.MqttClientConfiguration.PersistenceType; import org.eclipse.kura.core.util.ValidationUtil; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.data.DataTransportService; import org.eclipse.kura.data.DataTransportToken; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.eclipse.kura.ssl.SslManagerService; import org.eclipse.kura.ssl.SslServiceListener; import org.eclipse.kura.status.CloudConnectionStatusComponent; import org.eclipse.kura.status.CloudConnectionStatusEnum; import org.eclipse.kura.status.CloudConnectionStatusService; import org.eclipse.kura.system.SystemService; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.IMqttToken; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttClientPersistence; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.MqttPersistenceException; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.eclipse.paho.client.mqttv3.persist.MqttDefaultFilePersistence; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("java:S2789") public class MqttDataTransport implements DataTransportService, MqttCallback, ConfigurableComponent, SslServiceListener, CloudConnectionStatusComponent { private static final String NOT_CONNECTED_MESSAGE = "Not connected"; private static final String ALREADY_CONNECTED_MESSAGE = "Already connected"; private static final String INVALID_CONFIGURATION_MESSAGE = "Invalid configuration"; private static final Logger logger = LoggerFactory.getLogger(MqttDataTransport.class); private static final String MQTT_SCHEME = "mqtt://"; private static final String MQTTS_SCHEME = "mqtts://"; // '#' followed by one or more non-whitespace but not the '/' private static final String TOPIC_PATTERN_STRING = "#([^\\s/]+)"; private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING); private static final String MQTT_BROKER_URL_PROP_NAME = "broker-url"; private static final String MQTT_USERNAME_PROP_NAME = "username"; private static final String MQTT_PASSWORD_PROP_NAME = "password"; private static final String MQTT_CLIENT_ID_PROP_NAME = "client-id"; private static final String MQTT_KEEP_ALIVE_PROP_NAME = "keep-alive"; private static final String MQTT_CLEAN_SESSION_PROP_NAME = "clean-session"; // All timeouts private static final String MQTT_TIMEOUT_PROP_NAME = "timeout"; private static final String MQTT_DEFAULT_VERSION_PROP_NAME = "protocol-version"; private static final String MQTT_LWT_QOS_PROP_NAME = "lwt.qos"; private static final String MQTT_LWT_RETAIN_PROP_NAME = "lwt.retain"; private static final String MQTT_LWT_TOPIC_PROP_NAME = "lwt.topic"; private static final String MQTT_LWT_PAYLOAD_PROP_NAME = "lwt.payload"; private static final String CLOUD_ACCOUNT_NAME_PROP_NAME = "topic.context.account-name"; private static final String PERSISTENCE_TYPE_PROP_NAME = "in-flight.persistence"; private static final String TOPIC_ACCOUNT_NAME_CTX_NAME = "account-name"; private static final String TOPIC_DEVICE_ID_CTX_NAME = "client-id"; private static final long MQTT_QUIESCE_TIMEOUT = 2000; private static final long MQTT_DISCONNECT_TIMEOUT = 2000; private SystemService systemService; private Optional sslManagerService; private CloudConnectionStatusService cloudConnectionStatusService; private CloudConnectionStatusEnum notificationStatus = CloudConnectionStatusEnum.OFF; private MqttAsyncClient mqttClient; private DataTransportListenerS dataTransportListeners; private MqttClientConfiguration clientConf; private boolean newSession; private String sessionId; private PersistenceType persistenceType; private MqttClientPersistence persistence; private final Map topicContext = new HashMap<>(); private final Map properties = new HashMap<>(); private CryptoService cryptoService; private final Object updateLock = new Object(); // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { this.systemService = null; } public void setSslManagerService(SslManagerService sslManagerService) { final boolean update; synchronized (this.updateLock) { this.sslManagerService = Optional.of(sslManagerService); update = this.clientConf != null; } if (update) { update(); } } public void unsetSslManagerService(SslManagerService sslManagerService) { synchronized (this.updateLock) { if (Optional.of(sslManagerService).equals(this.sslManagerService)) { this.sslManagerService = Optional.empty(); } } } public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void unsetCryptoService(CryptoService cryptoService) { this.cryptoService = null; } public void setCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) { this.cloudConnectionStatusService = cloudConnectionStatusService; } public void unsetCloudConnectionStatusService(CloudConnectionStatusService cloudConnectionStatusService) { this.cloudConnectionStatusService = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map properties) { synchronized (this.updateLock) { logger.info("Activating {}...", properties.get(ConfigurationService.KURA_SERVICE_PID)); // We need to catch the configuration exception and activate anyway. // Otherwise the ConfigurationService will not be able to track us. HashMap decryptedPropertiesMap = new HashMap<>(); for (Map.Entry entry : properties.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (key.equals(MQTT_PASSWORD_PROP_NAME)) { try { Password decryptedPassword = new Password( this.cryptoService.decryptAes(((String) value).toCharArray())); decryptedPropertiesMap.put(key, decryptedPassword); } catch (Exception e) { logger.info("Password is not encrypted"); decryptedPropertiesMap.put(key, new Password((String) value)); } } else { decryptedPropertiesMap.put(key, value); } } this.properties.putAll(decryptedPropertiesMap); try { this.clientConf = buildConfiguration(this.properties); } catch (RuntimeException e) { logger.error( "Invalid client configuration. Service will not be able to connect until the configuration is updated", e); } this.dataTransportListeners = new DataTransportListenerS(componentContext); // Do nothing waiting for the connect request from the upper layer. } } protected void deactivate(ComponentContext componentContext) { logger.debug("Deactivating {}...", this.properties.get(ConfigurationService.KURA_SERVICE_PID)); // Before deactivating us, the OSGi container should have first // deactivated all dependent components. // They should be able to complete whatever is needed, // e.g. publishing a special last message, // synchronously in their deactivate method and disconnect us cleanly. // There shouldn't be anything to do here other then // perhaps forcibly disconnecting the MQTT client if not already done. if (isConnected()) { disconnect(0); } } public void updated(Map properties) { synchronized (this.updateLock) { logger.info("Updating {}...", properties.get(ConfigurationService.KURA_SERVICE_PID)); this.properties.clear(); HashMap decryptedPropertiesMap = new HashMap<>(); for (Map.Entry entry : properties.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); if (key.equals(MQTT_PASSWORD_PROP_NAME)) { try { Password decryptedPassword = new Password( this.cryptoService.decryptAes(((String) value).toCharArray())); decryptedPropertiesMap.put(key, decryptedPassword); } catch (Exception e) { logger.info("Password is not encrypted"); decryptedPropertiesMap.put(key, new Password((String) value)); } } else { decryptedPropertiesMap.put(key, value); } } this.properties.putAll(decryptedPropertiesMap); } update(); } private void update() { boolean wasConnected = isConnected(); // First notify the Listeners // We do nothing other than notifying the listeners which may later // request to disconnect and reconnect again. this.dataTransportListeners.onConfigurationUpdating(wasConnected); // Then update the configuration // Throwing a RuntimeException here is fine. // Listeners will not be notified of an invalid configuration update. logger.info("Building new configuration..."); synchronized (this.updateLock) { this.clientConf = buildConfiguration(this.properties); } // We do nothing other than notifying the listeners which may later // request to disconnect and reconnect again. this.dataTransportListeners.onConfigurationUpdated(wasConnected); } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public synchronized void connect() throws KuraConnectException { // We treat this as an application bug. if (isConnected()) { logger.error(ALREADY_CONNECTED_MESSAGE); throw new IllegalStateException(ALREADY_CONNECTED_MESSAGE); } // Attempt to setup the MQTT session try { setupMqttSession(); } catch (RuntimeException e) { throw new KuraConnectException(e, "Unexpected exception setting up MQTT session"); } if (this.mqttClient == null) { logger.error(INVALID_CONFIGURATION_MESSAGE); throw new IllegalStateException(INVALID_CONFIGURATION_MESSAGE); } logger.info("# ------------------------------------------------------------"); logger.info("# Connection Properties"); logger.info("# broker = {}", this.clientConf.getBrokerUrl()); logger.info("# clientId = {}", this.clientConf.getClientId()); logger.info("# username = {}", this.clientConf.getConnectOptions().getUserName()); logger.info("# password = XXXXXXXXXXXXXX"); logger.info("# keepAlive = {}", this.clientConf.getConnectOptions().getKeepAliveInterval()); logger.info("# timeout = {}", this.clientConf.getConnectOptions().getConnectionTimeout()); logger.info("# cleanSession = {}", this.clientConf.getConnectOptions().isCleanSession()); logger.info("# MQTT version = {}", getMqttVersionLabel(this.clientConf.getConnectOptions().getMqttVersion())); logger.info("# willDestination = {}", this.clientConf.getConnectOptions().getWillDestination()); logger.info("# willMessage = {}", this.clientConf.getConnectOptions().getWillMessage()); logger.info("#"); logger.info("# Connecting..."); // Register the component in the CloudConnectionStatus service this.cloudConnectionStatusService.register(this); // Update status notification service this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.FAST_BLINKING); // // connect try { IMqttToken connectToken = this.mqttClient.connect(this.clientConf.getConnectOptions()); connectToken.waitForCompletion(getTimeToWaitMillis() * 3); logger.info("# Connected!"); logger.info("# ------------------------------------------------------------"); // Update status notification service this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.ON); } catch (MqttException e) { logger.warn("xxxxx Connect failed. Forcing disconnect. xxxxx"); closeMqttClient(); // Update status notification service this.cloudConnectionStatusService.updateStatus(this, CloudConnectionStatusEnum.OFF); throw new KuraConnectException(e, "Cannot connect"); } finally { // Always unregister from CloudConnectionStatus service so to switch to the // previous state this.cloudConnectionStatusService.unregister(this); } // notify the listeners this.dataTransportListeners.onConnectionEstablished(this.newSession); } @Override public boolean isConnected() { if (this.mqttClient != null) { return this.mqttClient.isConnected(); } return false; } @Override public String getBrokerUrl() { if (this.clientConf != null) { String brokerUrl = this.clientConf.getBrokerUrl(); if (brokerUrl != null) { return brokerUrl; } } return ""; } @Override public String getAccountName() { if (this.clientConf != null) { String accountName = this.topicContext.get(TOPIC_ACCOUNT_NAME_CTX_NAME); if (accountName != null) { return accountName; } } return ""; } @Override public String getUsername() { if (this.clientConf != null) { String username = this.clientConf.getConnectOptions().getUserName(); if (username != null) { return username; } } return ""; } @Override public String getClientId() { if (this.clientConf != null) { String clientId = this.clientConf.getClientId(); if (clientId != null) { return clientId; } } return ""; } @Override public synchronized void disconnect(long quiesceTimeout) { // Disconnect the client if it's connected. If it fails log the // exception. // Don't throw an exception because the caller would not // be able to handle it. if (isConnected()) { logger.info("Disconnecting..."); // // notify the listeners this.dataTransportListeners.onDisconnecting(); try { this.mqttClient.disconnect(quiesceTimeout).waitForCompletion(getTimeToWaitMillis()); logger.info("Disconnected"); } catch (MqttException e) { logger.error("Disconnect failed", e); } // // notify the listeners this.dataTransportListeners.onDisconnected(); } else { logger.warn("MQTT client already disconnected"); } } // --------------------------------------------------------- // // Subscription Management Methods // // --------------------------------------------------------- @Override public void subscribe(String topic, int qos) throws KuraException { if (this.mqttClient == null || !this.mqttClient.isConnected()) { throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE); } topic = replaceTopicVariables(topic); logger.info("Subscribing to topic: {} with QoS: {}", topic, qos); try { IMqttToken token = this.mqttClient.subscribe(topic, qos); token.waitForCompletion(getTimeToWaitMillis()); } catch (MqttException e) { if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_TIMEOUT) { logger.warn("Timeout subscribing to topic: {}", topic); throw new KuraTimeoutException("Timeout subscribing to topic: " + topic, e); } else { logger.error("Cannot subscribe to topic: " + topic, e); throw KuraException.internalError(e, "Cannot subscribe to topic: " + topic); } } } @Override public void unsubscribe(String topic) throws KuraException { if (this.mqttClient == null || !this.mqttClient.isConnected()) { throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE); } topic = replaceTopicVariables(topic); logger.info("Unsubscribing to topic: {}", topic); try { IMqttToken token = this.mqttClient.unsubscribe(topic); token.waitForCompletion(getTimeToWaitMillis()); } catch (MqttException e) { if (e.getReasonCode() == MqttException.REASON_CODE_CLIENT_TIMEOUT) { logger.warn("Timeout unsubscribing to topic: {}", topic); throw new KuraTimeoutException("Timeout unsubscribing to topic: " + topic, e); } else { logger.error("Cannot unsubscribe to topic: " + topic, e); throw KuraException.internalError(e, "Cannot unsubscribe to topic: " + topic); } } } /* * (non-Javadoc) * * @see org.eclipse.kura.data.DataPublisherService#publish(java.lang.String * , byte[], int, boolean) * * DataConnectException this can be easily recovered connecting the service. * TooManyInflightMessagesException the caller SHOULD retry publishing the * message at a later time. RuntimeException (unchecked) all other * unrecoverable faults that are not recoverable by the caller. */ @Override public DataTransportToken publish(String topic, byte[] payload, int qos, boolean retain) throws KuraException { if (this.mqttClient == null || !this.mqttClient.isConnected()) { throw new KuraNotConnectedException(NOT_CONNECTED_MESSAGE); } topic = replaceTopicVariables(topic); logger.info("Publishing message on topic: {} with QoS: {}", topic, qos); MqttMessage message = new MqttMessage(); message.setPayload(payload); message.setQos(qos); message.setRetained(retain); Integer messageId = null; try { IMqttDeliveryToken token = this.mqttClient.publish(topic, message); // At present Paho ALWAYS allocates (gets and increments) internally // a message ID, // even for messages published with QoS == 0. // Of course, for QoS == 0 this "internal" message ID will not hit // the wire. // On top of that, messages published with QoS == 0 are confirmed // in the deliveryComplete callback. // Another implementation might behave differently // and only allocate a message ID for messages published with QoS > // 0. // We don't want to rely on this and only return and confirm IDs // of messages published with QoS > 0. logger.debug("Published message with ID: {}", token.getMessageId()); if (qos > 0) { messageId = Integer.valueOf(token.getMessageId()); } } catch (MqttPersistenceException e) { // This is probably an unrecoverable internal error logger.error("Cannot publish on topic: {}", topic, e); throw new IllegalStateException("Cannot publish on topic: " + topic); } catch (MqttException e) { if (e.getReasonCode() == MqttException.REASON_CODE_MAX_INFLIGHT) { logger.info("Too many inflight messages"); throw new KuraTooManyInflightMessagesException(e, "Too many in-fligh messages"); } else { logger.error("Cannot publish on topic: " + topic, e); throw KuraException.internalError(e, "Cannot publish on topic: " + topic); } } DataTransportToken token = null; if (messageId != null) { token = new DataTransportToken(messageId, this.sessionId); } return token; } @Override public void addDataTransportListener(DataTransportListener listener) { this.dataTransportListeners.add(listener); } @Override public void removeDataTransportListener(DataTransportListener listener) { this.dataTransportListeners.remove(listener); } // --------------------------------------------------------- // // MqttCallback methods // // --------------------------------------------------------- @Override public void connectionLost(final Throwable cause) { logger.warn("Connection Lost", cause); // notify the listeners this.dataTransportListeners.onConnectionLost(cause); } @Override public void deliveryComplete(IMqttDeliveryToken token) { if (token == null) { logger.error("null token"); return; } // Weird, tokens related to messages published with QoS > 0 have a null // nested message MqttMessage msg = null; try { msg = token.getMessage(); } catch (MqttException e) { logger.error("Cannot get message", e); return; } if (msg != null) { // Note that Paho call this also for messages published with QoS == // 0. // We don't want to rely on that and we drop asynchronous confirms // for QoS == 0. int qos = msg.getQos(); if (qos == 0) { logger.debug("Ignoring deliveryComplete for messages published with QoS == 0"); return; } } int id = token.getMessageId(); logger.debug("Delivery complete for message with ID: {}", id); // FIXME: We should be more selective here and only call the listener // that actually published the message. // Anyway we don't have such a mapping and so the publishers MUST track // their own // identifiers and filter confirms. // FIXME: it can happen that the listener that has published the message // has not come up yet. // This is the scenario: // * Paho has some in-flight messages. // * Kura gets stopped, crashes or the power is removed. // * Kura starts again, Paho connects and restores in-flight messages // from its persistence. // * These messages are delivered (this callback gets called) before the // publisher (also a DataPublisherListener) // * has come up (not yet tracked by the OSGi container). // These confirms will be lost! // notify the listeners DataTransportToken dataPublisherToken = new DataTransportToken(id, this.sessionId); this.dataTransportListeners.onMessageConfirmed(dataPublisherToken); } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { logger.debug("Message arrived on topic: {}", topic); // FIXME: we should be more selective here and only call the listeners // actually subscribed to this topic. // Anyway we don't have such a mapping so the listeners are responsible // to filter messages. // FIXME: the same argument about lost confirms applies to arrived // messages. // notify the listeners this.dataTransportListeners.onMessageArrived(topic, message.getPayload(), message.getQos(), message.isRetained()); } private long getTimeToWaitMillis() { // We use the same value for every timeout return this.clientConf.getConnectOptions().getConnectionTimeout() * 1000L; } // --------------------------------------------------------- // // SslServiceListener Overrides // // --------------------------------------------------------- @Override public void onConfigurationUpdated() { // The SSL service was updated, build a new socket connection and close the // current SSL client session if (this.mqttClient != null && isSSL(this.mqttClient.getServerURI())) { closeMqttClient(); } update(); } // --------------------------------------------------------- // // CloudConnectionStatus Overrides // // --------------------------------------------------------- @Override public int getNotificationPriority() { return CloudConnectionStatusService.PRIORITY_MEDIUM; } @Override public CloudConnectionStatusEnum getNotificationStatus() { return this.notificationStatus; } @Override public void setNotificationStatus(CloudConnectionStatusEnum status) { this.notificationStatus = status; } // --------------------------------------------------------- // // Private methods // // --------------------------------------------------------- /* * This method builds an internal configuration option needed by the client * to connect. The configuration is assembled from various sources: * component configuration, SystemService, NetworkService, etc. The returned * configuration is valid so no further validation is needed. If a valid * configuration cannot be assembled the method throws a RuntimeException * (assuming that this error is unrecoverable). */ private MqttClientConfiguration buildConfiguration(Map properties) { MqttClientConfiguration clientConfiguration; MqttConnectOptions conOpt = new MqttConnectOptions(); String clientId = null; String brokerUrl = null; try { // Configure the client ID clientId = (String) properties.get(MQTT_CLIENT_ID_PROP_NAME); if (clientId == null || clientId.trim().length() == 0) { clientId = this.systemService.getPrimaryMacAddress(); } ValidationUtil.notEmptyOrNull(clientId, "clientId"); // replace invalid token in the client ID as it is used as part of // the topicname space clientId = clientId.replace('/', '-'); clientId = clientId.replace('+', '-'); clientId = clientId.replace('#', '-'); clientId = clientId.replace('.', '-'); // Configure the broker URL brokerUrl = (String) properties.get(MQTT_BROKER_URL_PROP_NAME); ValidationUtil.notEmptyOrNull(brokerUrl, MQTT_BROKER_URL_PROP_NAME); brokerUrl = brokerUrl.trim(); brokerUrl = brokerUrl.replaceAll("^" + MQTT_SCHEME, "tcp://"); brokerUrl = brokerUrl.replaceAll("^" + MQTTS_SCHEME, "ssl://"); brokerUrl = brokerUrl.replaceAll("/$", ""); ValidationUtil.notEmptyOrNull(brokerUrl, "brokerUrl"); ValidationUtil.notNegative((Integer) properties.get(MQTT_KEEP_ALIVE_PROP_NAME), MQTT_KEEP_ALIVE_PROP_NAME); ValidationUtil.notNegative((Integer) properties.get(MQTT_TIMEOUT_PROP_NAME), MQTT_TIMEOUT_PROP_NAME); ValidationUtil.notNull(properties.get(MQTT_CLEAN_SESSION_PROP_NAME), MQTT_CLEAN_SESSION_PROP_NAME); String userName = (String) properties.get(MQTT_USERNAME_PROP_NAME); if (userName != null && !userName.isEmpty()) { conOpt.setUserName(userName); } Password password = (Password) properties.get(MQTT_PASSWORD_PROP_NAME); if (password != null && password.toString().length() != 0) { conOpt.setPassword(password.getPassword()); } conOpt.setKeepAliveInterval((Integer) properties.get(MQTT_KEEP_ALIVE_PROP_NAME)); conOpt.setConnectionTimeout((Integer) properties.get(MQTT_TIMEOUT_PROP_NAME)); conOpt.setCleanSession((Boolean) properties.get(MQTT_CLEAN_SESSION_PROP_NAME)); conOpt.setMqttVersion((Integer) properties.get(MQTT_DEFAULT_VERSION_PROP_NAME)); conOpt.setAutomaticReconnect(false); synchronized (this.topicContext) { this.topicContext.clear(); if (properties.get(CLOUD_ACCOUNT_NAME_PROP_NAME) != null) { this.topicContext.put(TOPIC_ACCOUNT_NAME_CTX_NAME, (String) properties.get(CLOUD_ACCOUNT_NAME_PROP_NAME)); } this.topicContext.put(TOPIC_DEVICE_ID_CTX_NAME, clientId); } String willTopic = (String) properties.get(MQTT_LWT_TOPIC_PROP_NAME); if (!(willTopic == null || willTopic.isEmpty())) { int willQos = 0; boolean willRetain = false; String willPayload = (String) properties.get(MQTT_LWT_PAYLOAD_PROP_NAME); if (properties.get(MQTT_LWT_QOS_PROP_NAME) != null) { willQos = (Integer) properties.get(MQTT_LWT_QOS_PROP_NAME); } if (properties.get(MQTT_LWT_RETAIN_PROP_NAME) != null) { willRetain = (Boolean) properties.get(MQTT_LWT_RETAIN_PROP_NAME); } willTopic = replaceTopicVariables(willTopic); byte[] payload = {}; if (willPayload != null && !willPayload.isEmpty()) { payload = willPayload.getBytes(StandardCharsets.UTF_8); } conOpt.setWill(willTopic, payload, willQos, willRetain); } } catch (KuraException e) { logger.error(INVALID_CONFIGURATION_MESSAGE); throw new IllegalStateException("Invalid MQTT client configuration", e); } // // SSL if (this.sslManagerService == null) { logger.warn("SSL Manager Service not yet initialized."); } else { if (isSSL(brokerUrl)) { if (this.sslManagerService.isPresent()) { try { SSLSocketFactory ssf = this.sslManagerService.get().getSSLSocketFactory(); conOpt.setSocketFactory(ssf); } catch (Exception e) { logger.error("SSL setup failed", e); throw new IllegalStateException("SSL setup failed"); } } else { logger.error("SSL Manager Service not selected."); } } } String sType = (String) properties.get(PERSISTENCE_TYPE_PROP_NAME); PersistenceType localPersistenceType = null; if ("file".equals(sType)) { localPersistenceType = PersistenceType.FILE; } else if ("memory".equals(sType)) { localPersistenceType = PersistenceType.MEMORY; } else { throw new IllegalStateException( "Invalid MQTT client configuration: persistenceType: " + localPersistenceType); } clientConfiguration = new MqttClientConfiguration(brokerUrl, clientId, localPersistenceType, conOpt); return clientConfiguration; } private boolean isSSL(String brokerUrl) { return brokerUrl.startsWith("ssl") || brokerUrl.startsWith("wss"); } private String replaceTopicVariables(String topic) { boolean found; Matcher topicMatcher = TOPIC_PATTERN.matcher(topic); StringBuffer sb = new StringBuffer(); do { found = topicMatcher.find(); if (found) { // By default replace #variable-name (group 0) with itself String replacement = topicMatcher.group(0); String variableName = topicMatcher.group(1); synchronized (this.topicContext) { String value = this.topicContext.get(variableName); if (value != null) { replacement = value; } } // Replace #variable-name with the value of the variable topicMatcher.appendReplacement(sb, replacement); } } while (found); topicMatcher.appendTail(sb); String replacedTopic = sb.toString(); logger.debug("Replaced tokens in topic {} with: {}", topic, replacedTopic); return replacedTopic; } private String generateSessionId() { return this.clientConf.getClientId() + "-" + this.clientConf.getBrokerUrl(); } private void setupMqttSession() { if (this.clientConf == null) { throw new IllegalStateException("Invalid client configuration"); } // We need to construct a new client instance only if either the broker URL // or the client ID changes. // We also need to construct a new instance if the persistence type (file or // memory) changes. // We MUST avoid to construct a new client instance every time because // in that case the MQTT message ID is reset to 1. if (this.mqttClient != null) { String brokerUrl = this.mqttClient.getServerURI(); String clientId = this.mqttClient.getClientId(); if (!(brokerUrl.equals(this.clientConf.getBrokerUrl()) && clientId.equals(this.clientConf.getClientId()) && this.persistenceType == this.clientConf.getPersistenceType())) { closeMqttClient(); } } // Connecting with Clean Session flag set to true always starts // a new session. boolean newSessionTemp = this.clientConf.getConnectOptions().isCleanSession(); if (this.mqttClient == null) { logger.info("Creating a new client instance"); // // Initialize persistence. This is only useful if the client // connects with // Clean Session flag set to false. // // Note that when using file peristence, // Paho creates a subdirectory persistence whose name is encoded // like this: // cristiano-tcpbroker-stageeveryware-cloudcom1883/ // So the persistence is per client ID (cristiano) and broker URL. // If we are connecting to a different broker URL or with a // different client ID, // Paho will create a new subdirectory for this MQTT connection. // Closing the old client instance also deletes the associated // persistence subdirectory. // // The lesson is: // Reconnecting to the same broker URL with the same client ID will // leverage // Paho persistence and the MQTT message ID is always increased (up // to the its maximum). // // Connecting either to a different broker URL or with a different // client ID discards persisted // messages and the MQTT client ID is reset. // // We have a problem here where the DataService needs to track // in-flight messages, possibly // across different MQTT connections. // These messages will never be confirmed on a different connection. // While we can assume that the client ID never changes because it's // typically auto-generated, // we cannot safely assume that the broker URL never changes. // // The above leads to two problems: // The MQTT message ID alone is not sufficient to track an in-flight // message // because it can be reset on a different connection. // // On a different connection the DataService should republish the // in-flight messages because // Paho won't do that. PersistenceType newPersistenceType = this.clientConf.getPersistenceType(); if (newPersistenceType == PersistenceType.MEMORY) { logger.info("Using memory persistence for in-flight messages"); this.persistence = new MemoryPersistence(); } else { StringBuffer sb = new StringBuffer(); sb.append(this.systemService.getKuraDataDirectory()).append(this.systemService.getFileSeparator()) .append("paho-persistence"); String dir = sb.toString(); logger.info("Using file persistence for in-flight messages: {}", dir); // Look for "Close on CONNACK timeout" FIXME in this file. // Make sure persistence is closed. // This is needed if the previous connect attempt was // forcibly terminated by closing the client. if (this.persistence != null) { try { this.persistence.close(); } catch (MqttPersistenceException e) { logger.warn("Failed to close persistence. Ignoring exception.", e); } } this.persistence = new MqttDefaultFilePersistence(dir); } // // Construct the MqttClient instance try { MqttAsyncClient newMqttClient = new MqttAsyncClient(this.clientConf.getBrokerUrl(), this.clientConf.getClientId(), this.persistence); newMqttClient.setCallback(this); this.mqttClient = newMqttClient; } catch (MqttException e) { logger.error("Client instantiation failed", e); throw new IllegalStateException("Client instantiation failed"); } this.persistenceType = newPersistenceType; if (!this.clientConf.getConnectOptions().isCleanSession()) { // This is tricky. // The purpose of this code is to try to restore pending delivery tokens // from the MQTT client persistence and determine if the next connection // can be considered continuing an existing session. // This is needed to allow the upper layer deciding what to do with the // in-flight messages it is tracking (if any). // If pending delivery tokens are found we assume that the upper layer // is tracking them. In this case we set the newSession flag to false // and notify this in the onConnectionEstablished callback. // The upper layer shouldn't do anything special. // // Otherwise the next upper layer should decide what to do with the // in-flight messages it is tracking (if any), either to republish or // drop them. IMqttDeliveryToken[] pendingDeliveryTokens = this.mqttClient.getPendingDeliveryTokens(); if (pendingDeliveryTokens != null && pendingDeliveryTokens.length != 0) { newSessionTemp = false; } } } this.newSession = newSessionTemp; this.sessionId = generateSessionId(); } private void closeMqttClient() { if (this.mqttClient == null) { return; } try { logger.info("Forcing client disconnect..."); this.mqttClient.disconnectForcibly(MQTT_QUIESCE_TIMEOUT, MQTT_DISCONNECT_TIMEOUT); } catch (Exception e) { logger.warn("Cannot force client disconnect", e); } try { logger.info("Closing client..."); // prevent callbacks from a zombie client this.mqttClient.setCallback(null); this.mqttClient.close(); logger.info("Closed"); } catch (Exception e) { logger.warn("Cannot close client", e); } finally { this.mqttClient = null; } } private static String getMqttVersionLabel(int mqttVersion) { switch (mqttVersion) { case MqttConnectOptions.MQTT_VERSION_3_1: return "3.1"; case MqttConnectOptions.MQTT_VERSION_3_1_1: return "3.1.1"; default: return String.valueOf(mqttVersion); } } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/data/util/MqttTopicUtil.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.data.util; import org.eclipse.paho.client.mqttv3.MqttTopic; public final class MqttTopicUtil { private MqttTopicUtil() { } public static void validate(final String topicString, final boolean wildcardAllowed) { MqttTopic.validate(topicString, wildcardAllowed); } public static boolean isMatched(final String topicFilter, final String topicName) { return MqttTopic.isMatched(topicFilter, topicName); } } ================================================ FILE: kura/org.eclipse.kura.cloud.base.provider/src/main/java/org/eclipse/kura/core/internal/data/TokenBucket.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.internal.data; public class TokenBucket { private final int capacity; private final long refillPeriod; private int remainingTokens; private long lastRefillTime; public TokenBucket(int capacity, long refillPeriod) { this.capacity = capacity; this.remainingTokens = capacity; this.refillPeriod = refillPeriod; this.lastRefillTime = System.nanoTime(); } public boolean getToken() { boolean result = false; refill(); if (isTokenAvailable()) { this.remainingTokens--; result = true; } return result; } private boolean isTokenAvailable() { return this.remainingTokens != 0; } private void refill() { long now = System.nanoTime(); if (now - this.lastRefillTime >= this.refillPeriod) { this.remainingTokens = (int) Math.min(this.capacity, this.remainingTokens + (now - this.lastRefillTime) / this.refillPeriod); this.remainingTokens = Math.max(1, this.remainingTokens); this.lastRefillTime += (now - this.lastRefillTime) / this.refillPeriod * this.refillPeriod; } } public long getTokenWaitTime() { long now = System.nanoTime(); long timeToRefill = this.lastRefillTime + this.refillPeriod - now; return Math.max(0, timeToRefill); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/.gitignore ================================================ /target /bin /lib ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Connection Provider for the Eclipse IoT Cloud Platform Bundle-SymbolicName: org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: ., lib/protobuf-java.jar Bundle-ActivationPolicy: lazy Import-Package: com.eclipsesource.json;version="0.9.5", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.audit;version="[1.0,2.0)", org.eclipse.kura.certificate;version="[2.0,3.0)", org.eclipse.kura.cloud;version="[1.1,1.2)", org.eclipse.kura.cloudconnection;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.factory;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.listener;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.request;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.subscriber.listener;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.configuration.metatype;version="[1.1,2.0)", org.eclipse.kura.core.data;version="[1.0,2.0)", org.eclipse.kura.core.util;version="[2.0,3.0)", org.eclipse.kura.data;version="[1.0,2.0)", org.eclipse.kura.data.listener;version="[1.0,1.1)", org.eclipse.kura.marshalling;version="[1.0,2.0)", org.eclipse.kura.message;version="[1.5,2.0)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.net.modem;version="[2.0,3.0)", org.eclipse.kura.net.status;version="[1.1,2.0)", org.eclipse.kura.net.status.modem;version="[1.0,2.0)", org.eclipse.kura.position;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.0", org.osgi.util.measurement;version="[1.0,2.0)", org.osgi.util.position;version="[1.0,2.0)", org.osgi.util.tracker;version="1.5.1", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloud.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloudConnectionFactory.xml ================================================ createConfiguration ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/cloudPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.CloudPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ lib/protobuf-java.jar src.includes = about.html,\ about_files/ source.. = src/main/java/ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. com.google.protobuf protobuf-java maven-dependency-plugin 3.8.1 copy-dependencies generate-sources copy-dependencies ${project.basedir}/lib protobuf-java true org.apache.maven.plugins maven-checkstyle-plugin true maven-clean-plugin 3.1.0 lib ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudConnectionManagerImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import static java.util.Objects.nonNull; import static org.eclipse.kura.cloud.CloudPayloadEncoding.KURA_PROTOBUF; import static org.eclipse.kura.cloud.CloudPayloadEncoding.SIMPLE_JSON; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.FULL_TOPIC; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.PRIORITY; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.QOS; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.RETAIN; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraInvalidMessageException; import org.eclipse.kura.certificate.CertificatesService; import org.eclipse.kura.cloud.CloudConnectionEstablishedEvent; import org.eclipse.kura.cloud.CloudConnectionLostEvent; import org.eclipse.kura.cloud.CloudPayloadEncoding; import org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder; import org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.data.DataServiceImpl; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.message.KuraApplicationTopic; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.net.NetworkService; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.eclipse.kura.net.status.NetworkStatusService; import org.eclipse.kura.net.status.modem.ModemInterfaceStatus; import org.eclipse.kura.net.status.modem.Sim; import org.eclipse.kura.position.PositionLockedEvent; import org.eclipse.kura.position.PositionService; import org.eclipse.kura.system.SystemAdminService; import org.eclipse.kura.system.SystemService; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudConnectionManagerImpl implements DataServiceListener, ConfigurableComponent, EventHandler, CloudPayloadProtoBufEncoder, CloudPayloadProtoBufDecoder, RequestHandlerRegistry, CloudConnectionManager, CloudEndpoint { private static final String KURA_PAYLOAD = "KuraPayload"; private static final String SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE = "Cannot setup cloud service connection"; private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerImpl.class); private static final String CONNECTION_EVENT_PID_PROPERTY_KEY = "cloud.service.pid"; static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL = "org/osgi/service/deployment/INSTALL"; static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL = "org/osgi/service/deployment/UNINSTALL"; private static final int NUM_CONCURRENT_CALLBACKS = 2; private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS); private ComponentContext ctx; private CloudConnectionManagerOptions options; private DataService dataService; private SystemService systemService; private SystemAdminService systemAdminService; private Optional networkService = Optional.empty(); private Optional positionService = Optional.empty(); private EventAdmin eventAdmin; private CertificatesService certificatesService; private Unmarshaller jsonUnmarshaller; private Marshaller jsonMarshaller; private Optional networkStatusService = Optional.empty(); // package visibility for LifeCyclePayloadBuilder String imei; String iccid; String imsi; String rssi; String modemFwVer; private String ownPid; private final AtomicInteger messageId; private ServiceRegistration cloudServiceRegistration; private final Map registeredRequestHandlers; private final Set registeredCloudConnectionListeners; private final Set registeredCloudPublisherDeliveryListeners; private final Set registeredCloudDeliveryListeners; private ScheduledFuture scheduledBirthPublisherFuture; private ScheduledExecutorService scheduledBirthPublisher = Executors.newScheduledThreadPool(1); public CloudConnectionManagerImpl() { this.messageId = new AtomicInteger(); this.registeredCloudConnectionListeners = new CopyOnWriteArraySet<>(); this.registeredRequestHandlers = new HashMap<>(); this.registeredCloudPublisherDeliveryListeners = new CopyOnWriteArraySet<>(); this.registeredCloudDeliveryListeners = new CopyOnWriteArraySet<>(); } // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setDataService(DataService dataService) { this.dataService = dataService; } public void unsetDataService(DataService dataService) { if (this.dataService.equals(dataService)) { this.dataService = null; } } public DataService getDataService() { return this.dataService; } public void setSystemAdminService(SystemAdminService systemAdminService) { this.systemAdminService = systemAdminService; } public void unsetSystemAdminService(SystemAdminService systemAdminService) { if (this.systemAdminService.equals(systemAdminService)) { this.systemAdminService = null; } } public SystemAdminService getSystemAdminService() { return this.systemAdminService; } public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { if (this.systemService.equals(systemService)) { this.systemService = null; } } public SystemService getSystemService() { return this.systemService; } public void setNetworkService(NetworkService networkService) { this.networkService = Optional.of(networkService); } public void unsetNetworkService(NetworkService networkService) { if (this.networkService.isPresent() && this.networkService.get().equals(networkService)) { this.networkService = Optional.empty(); } } public Optional getNetworkService() { return this.networkService; } public void setPositionService(PositionService positionService) { this.positionService = Optional.of(positionService); } public void unsetPositionService(PositionService positionService) { if (this.positionService.isPresent() && this.positionService.get().equals(positionService)) { this.positionService = Optional.empty(); } } public Optional getPositionService() { return this.positionService; } public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void unsetEventAdmin(EventAdmin eventAdmin) { if (this.eventAdmin.equals(eventAdmin)) { this.eventAdmin = null; } } public void setJsonUnmarshaller(Unmarshaller jsonUnmarshaller) { this.jsonUnmarshaller = jsonUnmarshaller; } public void unsetJsonUnmarshaller(Unmarshaller jsonUnmarshaller) { if (this.jsonUnmarshaller.equals(jsonUnmarshaller)) { this.jsonUnmarshaller = null; } } public void setJsonMarshaller(Marshaller jsonMarshaller) { this.jsonMarshaller = jsonMarshaller; } public void unsetJsonMarshaller(Marshaller jsonMarshaller) { if (this.jsonMarshaller.equals(jsonMarshaller)) { this.jsonMarshaller = null; } } public void setNetworkStatusService(NetworkStatusService networkStatusService) { this.networkStatusService = Optional.of(networkStatusService); } public void unsetNetworkStatusService(NetworkStatusService networkStatusService) { if (this.networkStatusService.isPresent() && this.networkStatusService.get().equals(networkStatusService)) { this.networkStatusService = Optional.empty(); } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map properties) { this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("activate {}...", ownPid); // // save the bundle context and the properties this.ctx = componentContext; this.options = new CloudConnectionManagerOptions(properties, this.systemService); // // install event listener for GPS locked event Dictionary props = new Hashtable<>(); String[] eventTopics = { PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC, EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL, EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL }; props.put(EventConstants.EVENT_TOPIC, eventTopics); this.cloudServiceRegistration = this.ctx.getBundleContext().registerService(EventHandler.class.getName(), this, props); this.dataService.addDataServiceListener(this); // // Usually the cloud connection is setup in the // onConnectionEstablished callback. // Since the callback may be lost if we are activated // too late (the DataService is already connected) we // setup the cloud connection here. if (isConnected()) { logger.warn("DataService is already connected. Publish BIRTH certificate"); try { setupCloudConnection(false); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE, e); } } } public void updated(Map properties) { logger.info("updated {}...: {}", properties.get(ConfigurationService.KURA_SERVICE_PID), properties); // Update properties and re-publish Birth certificate this.options = new CloudConnectionManagerOptions(properties, this.systemService); if (isConnected()) { try { setupCloudConnection(false); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE); } } } protected void deactivate(ComponentContext componentContext) { logger.info("deactivate {}...", componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID)); if (isConnected()) { try { publishDisconnectCertificate(); } catch (KuraException e) { logger.warn("Cannot publish disconnect certificate"); } } this.dataService.removeDataServiceListener(this); this.dataService = null; this.systemService = null; this.systemAdminService = null; this.networkService = null; this.positionService = Optional.empty(); this.eventAdmin = null; this.cloudServiceRegistration.unregister(); } @Override public void handleEvent(Event event) { String topic = event.getTopic(); if (PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC.contains(topic)) { handlePositionLockedEvent(); return; } if ((EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL.equals(topic) || EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL.equals(topic)) && this.dataService.isConnected()) { logger.debug("CloudConnectionManagerImpl: received install/uninstall event, publishing BIRTH."); tryPublishBirthCertificate(false); } } private void handlePositionLockedEvent() { // if we get a position locked event, // republish the birth certificate only if we are configured to logger.info("Handling PositionLockedEvent"); if (this.dataService.isConnected() && this.options.getRepubBirthCertOnGpsLock()) { tryPublishBirthCertificate(false); } } private void tryPublishBirthCertificate(boolean isNewConnection) { try { publishBirthCertificate(isNewConnection); } catch (KuraException e) { logger.warn("Cannot publish birth certificate", e); } } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public boolean isConnected() { return this.dataService != null && this.dataService.isConnected(); } // ---------------------------------------------------------------- // // Package APIs // // ---------------------------------------------------------------- public CloudConnectionManagerOptions getCloudConnectionManagerOptions() { return this.options; } public byte[] encodePayload(KuraPayload payload) throws KuraException { byte[] bytes; CloudPayloadEncoding preferencesEncoding = this.options.getPayloadEncoding(); if (preferencesEncoding == KURA_PROTOBUF) { bytes = encodeProtobufPayload(payload); } else if (preferencesEncoding == SIMPLE_JSON) { bytes = encodeJsonPayload(payload); } else { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD); } return bytes; } // ---------------------------------------------------------------- // // DataServiceListener API // // ---------------------------------------------------------------- @Override public void onConnectionEstablished() { try { setupCloudConnection(true); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE); } postConnectionStateChangeEvent(true); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished); } @Override public void onDisconnecting() { // publish disconnect certificate try { publishDisconnectCertificate(); } catch (KuraException e) { logger.warn("Cannot publish disconnect certificate"); } } @Override public void onDisconnected() { // raise event postConnectionStateChangeEvent(false); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected); } @Override public void onConnectionLost(Throwable cause) { // raise event postConnectionStateChangeEvent(false); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { logger.info("Message arrived on topic: {}", topic); // notify listeners ControlTopic kuraTopic = new ControlTopic(topic, MessageType.CONTROL.getTopicPrefix()); KuraPayload kuraPayload = null; if (this.options.getPayloadEncoding() == SIMPLE_JSON) { try { kuraPayload = createKuraPayloadFromJson(payload); } catch (KuraException e) { logger.warn("Error creating Kura Payload from Json", e); } } else if (this.options.getPayloadEncoding() == KURA_PROTOBUF) { kuraPayload = createKuraPayloadFromProtoBuf(topic, payload); } try { boolean validMessage = isValidMessage(kuraTopic, kuraPayload); if (validMessage) { dispatchControlMessage(kuraTopic, kuraPayload); } else { logger.warn("Message verification failed! Not valid signature or message not signed."); } } catch (Exception e) { logger.error("Error during CloudClientListener notification.", e); } } private void dispatchControlMessage(ControlTopic kuraTopic, KuraPayload kuraPayload) { String applicationId = kuraTopic.getApplicationId(); kuraPayload.addMetric(MessageHandlerCallable.METRIC_REQUEST_ID, kuraTopic.getReqId()); RequestHandler cloudlet = this.registeredRequestHandlers.get(applicationId); if (cloudlet != null) { callbackExecutor .submit(new MessageHandlerCallable(cloudlet, kuraTopic.getApplicationTopic(), kuraPayload, this)); } } private boolean isValidMessage(KuraApplicationTopic kuraAppTopic, KuraPayload kuraPayload) { if (this.certificatesService == null) { ServiceReference sr = this.ctx.getBundleContext() .getServiceReference(CertificatesService.class); if (sr != null) { this.certificatesService = this.ctx.getBundleContext().getService(sr); } } boolean validMessage = false; if (this.certificatesService == null || this.certificatesService.verifySignature(kuraAppTopic, kuraPayload)) { validMessage = true; } return validMessage; } @Override public void onMessagePublished(int messageId, String topic) { synchronized (this.messageId) { if (this.messageId.get() != -1 && this.messageId.get() == messageId) { if (this.options.getLifeCycleMessageQos() == 0) { this.messageId.set(-1); } this.messageId.notifyAll(); } } } @Override public void onMessageConfirmed(int messageId, String topic) { synchronized (this.messageId) { if (this.messageId.get() != -1 && this.messageId.get() == messageId) { this.messageId.set(-1); this.messageId.notifyAll(); } } this.registeredCloudPublisherDeliveryListeners .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId), topic)); this.registeredCloudDeliveryListeners .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId))); } // ---------------------------------------------------------------- // // CloudPayloadProtoBufEncoder API // // ---------------------------------------------------------------- @Override public byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException { CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(kuraPayload); if (gzipped) { encoder = new CloudPayloadGZipEncoder(encoder); } byte[] bytes; try { bytes = encoder.getBytes(); return bytes; } catch (IOException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e); } } // ---------------------------------------------------------------- // // CloudPayloadProtoBufDecoder API // // ---------------------------------------------------------------- @Override public KuraPayload buildFromByteArray(byte[] payload) throws KuraException { CloudPayloadProtoBufDecoderImpl encoder = new CloudPayloadProtoBufDecoderImpl(payload); KuraPayload kuraPayload; try { kuraPayload = encoder.buildFromByteArray(); return kuraPayload; } catch (KuraInvalidMessageException | IOException e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, KURA_PAYLOAD, e); } } // ---------------------------------------------------------------- // // Birth and Disconnect Certificates // // ---------------------------------------------------------------- private void setupCloudConnection(boolean isNewConnection) throws KuraException { publishBirthCertificate(isNewConnection); setupDeviceSubscriptions(); } private void setupDeviceSubscriptions() throws KuraException { StringBuilder sbDeviceSubscription = new StringBuilder(); sbDeviceSubscription.append(MessageType.CONTROL.getTopicPrefix()).append(this.options.getTopicSeparator()) .append("+").append(this.options.getTopicSeparator()).append("+") .append(this.options.getTopicSeparator()).append("req").append(this.options.getTopicSeparator()) .append(this.options.getTopicWildCard()); this.dataService.subscribe(sbDeviceSubscription.toString(), 0); } private void publishBirthCertificate(boolean isNewConnection) throws KuraException { if (isFrameworkStopping()) { logger.info("framework is stopping.. not republishing birth certificate"); return; } readModemProfile(); LifecycleMessage birthToPublish = new LifecycleMessage(this.options, this).asBirthCertificateMessage(); if (isNewConnection) { publishLifeCycleMessage(birthToPublish); } else { publishWithDelay(birthToPublish); } } private void publishDisconnectCertificate() throws KuraException { publishLifeCycleMessage(new LifecycleMessage(this.options, this).asDisconnectCertificateMessage()); } private void publishWithDelay(LifecycleMessage message) { if (Objects.nonNull(this.scheduledBirthPublisherFuture)) { this.scheduledBirthPublisherFuture.cancel(false); logger.debug("CloudConnectionManagerImpl: BIRTH message cache timer restarted."); } logger.debug("CloudConnectionManagerImpl: BIRTH message cached for 30s."); this.scheduledBirthPublisherFuture = this.scheduledBirthPublisher.schedule(() -> { try { logger.debug("CloudConnectionManagerImpl: publishing cached BIRTH message."); publishLifeCycleMessage(message); } catch (KuraException e) { logger.error("Error sending cached BIRTH/APP certificate.", e); } }, 30L, TimeUnit.SECONDS); } private void publishLifeCycleMessage(LifecycleMessage message) throws KuraException { // track the message ID and block until the message // has been published (i.e. written to the socket). synchronized (this.messageId) { this.messageId.set(-1); // add a timestamp to the message KuraPayload payload = message.getPayload(); payload.setTimestamp(new Date()); byte[] encodedPayload = encodePayload(payload); int localMessageId = this.dataService.publish(message.getTopic(), encodedPayload, this.options.getLifeCycleMessageQos(), this.options.getLifeCycleMessageRetain(), this.options.getLifeCycleMessagePriority()); this.messageId.set(localMessageId); try { this.messageId.wait(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.info("Interrupted while waiting for the message to be published", e); } } } private byte[] encodeProtobufPayload(KuraPayload payload) throws KuraException { byte[] bytes = new byte[0]; if (payload == null) { return bytes; } CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(payload); if (this.options.getEncodeGzip()) { encoder = new CloudPayloadGZipEncoder(encoder); } try { bytes = encoder.getBytes(); } catch (IOException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e); } return bytes; } private byte[] encodeJsonPayload(KuraPayload payload) throws KuraException { return this.jsonMarshaller.marshal(payload).getBytes(StandardCharsets.UTF_8); } private KuraPayload createKuraPayloadFromJson(byte[] payload) throws KuraException { return this.jsonUnmarshaller.unmarshal(new String(payload), KuraPayload.class); } private KuraPayload createKuraPayloadFromProtoBuf(String topic, byte[] payload) { KuraPayload kuraPayload; try { // try to decode the message into an KuraPayload kuraPayload = new CloudPayloadProtoBufDecoderImpl(payload).buildFromByteArray(); } catch (Exception e) { // Wrap the received bytes payload into an KuraPayload logger.debug("Received message on topic {} that could not be decoded. Wrapping it into an KuraPayload.", topic); kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); } return kuraPayload; } private void postConnectionStateChangeEvent(final boolean isConnected) { final Map eventProperties = Collections.singletonMap(CONNECTION_EVENT_PID_PROPERTY_KEY, (String) this.ctx.getProperties().get(ConfigurationService.KURA_SERVICE_PID)); final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties) : new CloudConnectionLostEvent(eventProperties); this.eventAdmin.postEvent(event); } @Override public void connect() throws KuraConnectException { if (this.dataService != null) { this.dataService.connect(); } } @Override public void disconnect() { if (this.dataService != null) { this.dataService.disconnect(10); } } @Override public Map getInfo() { DataServiceImpl dataServiceImpl = (DataServiceImpl) this.dataService; return dataServiceImpl.getConnectionInfo(); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.registeredCloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.registeredCloudConnectionListeners.remove(cloudConnectionListener); } public void registerCloudPublisherDeliveryListener(CloudPublisherDeliveryListener cloudPublisherDeliveryListener) { this.registeredCloudPublisherDeliveryListeners.add(cloudPublisherDeliveryListener); } public void unregisterCloudPublisherDeliveryListener( CloudPublisherDeliveryListener cloudPublisherDeliveryListener) { this.registeredCloudPublisherDeliveryListeners.remove(cloudPublisherDeliveryListener); } @Override public String publish(KuraMessage message) throws KuraException { Map messageProps = message.getProperties(); String fullTopic = (String) messageProps.get(FULL_TOPIC.name()); int qos = (Integer) messageProps.get(QOS.name()); boolean retain = (Boolean) messageProps.get(RETAIN.name()); int priority = (Integer) messageProps.get(PRIORITY.name()); byte[] appPayload = encodePayload(message.getPayload()); int id = this.dataService.publish(fullTopic, appPayload, qos, retain, priority); if (qos == 0) { return null; } return String.valueOf(id); } String getOwnPid() { return ownPid; } @Override public void registerSubscriber(Map subscriptionProperties, CloudSubscriberListener subscriber) { throw new UnsupportedOperationException(); } @Override public void unregisterSubscriber(CloudSubscriberListener subscriberListener) { throw new UnsupportedOperationException(); } @Override public void registerRequestHandler(String id, RequestHandler requestHandler) throws KuraException { this.registeredRequestHandlers.put(id, requestHandler); } @Override public void unregister(String id) throws KuraException { this.registeredRequestHandlers.remove(id); } public String getNotificationPublisherPid() { throw new UnsupportedOperationException(); } public CloudNotificationPublisher getNotificationPublisher() { throw new UnsupportedOperationException(); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.registeredCloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.registeredCloudDeliveryListeners.remove(cloudDeliveryListener); } private boolean isFrameworkStopping() { try { final Bundle ownBundle = FrameworkUtil.getBundle(CloudConnectionManagerImpl.class); if (ownBundle == null) { return false; // not running in an OSGi framework? e.g. unit test } return ownBundle.getBundleContext().getBundle(0).getState() == Bundle.STOPPING; } catch (final Exception e) { logger.warn("unexpected exception while checking if framework is shutting down", e); return false; } } private void readModemProfile() { this.networkStatusService.ifPresent(statusService -> { List modemStatuses = getModemsStatuses(statusService); if (nonNull(modemStatuses) && !modemStatuses.isEmpty()) { readModemInfos(modemStatuses); } else { this.imei = null; this.iccid = null; this.imsi = null; this.rssi = null; this.modemFwVer = null; } }); } private List getModemsStatuses(NetworkStatusService networkStatusService) { List modemStatuses = new ArrayList<>(); try { List interfaceIds = networkStatusService.getInterfaceIds(); for (String interfaceId : interfaceIds) { Optional networkInterfaceStatus = networkStatusService .getNetworkStatus(interfaceId); networkInterfaceStatus.ifPresent(state -> { NetworkInterfaceType type = state.getType(); if (NetworkInterfaceType.MODEM.equals(type)) { modemStatuses.add((ModemInterfaceStatus) state); } }); } } catch (KuraException e) { logger.error("Error reading modem profile", e); } return modemStatuses; } private void readModemInfos(List modemStatuses) { Collections.sort(modemStatuses, Comparator.comparing(ModemInterfaceStatus::getConnectionStatus)); ModemInterfaceStatus modemStatus = modemStatuses.get(modemStatuses.size() - 1); Optional activeSim = Optional.empty(); List availableSims = modemStatus.getAvailableSims(); for (Sim sim : availableSims) { if (sim.isActive() && sim.isPrimary()) { activeSim = Optional.of(sim); } } this.iccid = "NA"; this.imsi = "NA"; activeSim.ifPresent(sim -> { this.iccid = sim.getIccid(); this.imsi = sim.getImsi(); }); this.imei = modemStatus.getSerialNumber(); this.rssi = String.valueOf(modemStatus.getSignalStrength()); this.modemFwVer = modemStatus.getFirmwareVersion(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudConnectionManagerOptions.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.util.Map; import org.eclipse.kura.cloud.CloudPayloadEncoding; import org.eclipse.kura.system.SystemService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudConnectionManagerOptions { private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerOptions.class); private static final String TOPIC_SEPARATOR = "/"; private static final String TOPIC_BIRTH_SUFFIX = "MQTT/BIRTH"; private static final String TOPIC_DISCONNECT_SUFFIX = "MQTT/DC"; private static final String TOPIC_APPS_SUFFIX = "MQTT/APPS"; private static final String TOPIC_WILD_CARD = "#"; private static final String DEVICE_DISPLAY_NAME = "device.display-name"; private static final String DEVICE_CUSTOM_NAME = "device.custom-name"; private static final String ENCODE_GZIP = "encode.gzip"; private static final String REPUB_BIRTH_ON_GPS_LOCK = "republish.mqtt.birth.cert.on.gps.lock"; private static final String PAYLOAD_ENCODING = "payload.encoding"; private static final int LIFECYCLE_QOS = 1; private static final int LIFECYCLE_PRIORITY = 0; private static final boolean LIFECYCLE_RETAIN = false; private final Map properties; private final SystemService systemService; CloudConnectionManagerOptions(Map properties, SystemService systemService) { this.properties = properties; this.systemService = systemService; } /** * Returns the display name for the device. * * @return a String value. */ public String getDeviceDisplayName() { String displayName = ""; if (this.properties == null) { return displayName; } String deviceDisplayNameOption = (String) this.properties.get(DEVICE_DISPLAY_NAME); // Use the device name from SystemService. This should be kura.device.name from // the properties file. if ("device-name".equals(deviceDisplayNameOption)) { displayName = this.systemService.getDeviceName(); } // Try to get the device hostname else if ("hostname".equals(deviceDisplayNameOption)) { displayName = this.systemService.getHostname(); } // Return the custom field defined by the user else if ("custom".equals(deviceDisplayNameOption) && this.properties.get(DEVICE_CUSTOM_NAME) instanceof String) { displayName = (String) this.properties.get(DEVICE_CUSTOM_NAME); } // Return empty string to the server else if ("server".equals(deviceDisplayNameOption)) { displayName = ""; } return displayName; } /** * Returns true if the current CloudService configuration * specifies Gzip compression enabled for outgoing payloads. * * @return a boolean value. */ public boolean getEncodeGzip() { boolean encodeGzip = false; if (this.properties != null && this.properties.get(ENCODE_GZIP) != null && this.properties.get(ENCODE_GZIP) instanceof Boolean) { encodeGzip = (Boolean) this.properties.get(ENCODE_GZIP); } return encodeGzip; } /** * Returns true if the current CloudService configuration * specifies the cloud client should republish the MQTT birth * certificate on GPS lock events. * * @return a boolean value. */ public boolean getRepubBirthCertOnGpsLock() { boolean repubBirth = false; if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) != null && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) instanceof Boolean) { repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_GPS_LOCK); } return repubBirth; } /** * This method parses the Cloud Service configuration and returns the selected cloud payload encoding. * By default, this method returns {@link CloudPayloadEncoding} {@code KURA_PROTOBUF}. * * @return a boolean value. */ public CloudPayloadEncoding getPayloadEncoding() { CloudPayloadEncoding result = CloudPayloadEncoding.KURA_PROTOBUF; String encodingString = ""; if (this.properties != null && this.properties.get(PAYLOAD_ENCODING) != null && this.properties.get(PAYLOAD_ENCODING) instanceof String) { encodingString = (String) this.properties.get(PAYLOAD_ENCODING); } try { result = CloudPayloadEncoding.getEncoding(encodingString); } catch (IllegalArgumentException e) { logger.warn("Cannot parse the provided payload encoding.", e); } return result; } public String getTopicSeparator() { return TOPIC_SEPARATOR; } public String getTopicBirthSuffix() { return TOPIC_BIRTH_SUFFIX; } public String getTopicDisconnectSuffix() { return TOPIC_DISCONNECT_SUFFIX; } public String getTopicAppsSuffix() { return TOPIC_APPS_SUFFIX; } public String getTopicWildCard() { return TOPIC_WILD_CARD; } public int getLifeCycleMessageQos() { return LIFECYCLE_QOS; } public int getLifeCycleMessagePriority() { return LIFECYCLE_PRIORITY; } public boolean getLifeCycleMessageRetain() { return LIFECYCLE_RETAIN; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.io.IOException; /** * Common interface for the PayloadEncoders */ @FunctionalInterface public interface CloudPayloadEncoder { public byte[] getBytes() throws IOException; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadGZipEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.io.IOException; import org.eclipse.kura.core.util.GZipUtil; public class CloudPayloadGZipEncoder implements CloudPayloadEncoder { private final CloudPayloadEncoder decorated; public CloudPayloadGZipEncoder(CloudPayloadEncoder decorated) { this.decorated = decorated; } @Override public byte[] getBytes() throws IOException { byte[] source = this.decorated.getBytes(); byte[] compressed = GZipUtil.compress(source); // Return gzip compressed data only if shorter than uncompressed one return compressed.length < source.length ? compressed : source; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadProtoBufDecoderImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.io.IOException; import java.util.Date; import org.eclipse.kura.KuraInvalidMessageException; import org.eclipse.kura.KuraInvalidMetricTypeException; import org.eclipse.kura.core.util.GZipUtil; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraPosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; public class CloudPayloadProtoBufDecoderImpl { private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufDecoderImpl.class); private byte[] bytes; public CloudPayloadProtoBufDecoderImpl(byte[] bytes) { this.bytes = bytes; } /** * Factory method to build an KuraPayload instance from a byte array. * * @param bytes * @return * @throws InvalidProtocolBufferException * @throws IOException */ public KuraPayload buildFromByteArray() throws IOException { // Check if a compressed payload and try to decompress it if (GZipUtil.isCompressed(this.bytes)) { try { this.bytes = GZipUtil.decompress(this.bytes); } catch (IOException e) { logger.info("Decompression failed"); // do not rethrow the exception here as isCompressed may return some false positives } } // build the KuraPayloadProto.KuraPayload KuraPayloadProto.KuraPayload protoMsg = null; try { protoMsg = KuraPayloadProto.KuraPayload.parseFrom(this.bytes); } catch (InvalidProtocolBufferException ipbe) { throw new KuraInvalidMessageException(ipbe); } // build the KuraPayload KuraPayload kuraMsg = new KuraPayload(); // set the timestamp if (protoMsg.hasTimestamp()) { kuraMsg.setTimestamp(new Date(protoMsg.getTimestamp())); } // set the position if (protoMsg.hasPosition()) { kuraMsg.setPosition(buildFromProtoBuf(protoMsg.getPosition())); } // set the metrics for (int i = 0; i < protoMsg.getMetricCount(); i++) { String name = protoMsg.getMetric(i).getName(); try { Object value = getProtoKuraMetricValue(protoMsg.getMetric(i), protoMsg.getMetric(i).getType()); kuraMsg.addMetric(name, value); } catch (KuraInvalidMetricTypeException ihte) { logger.warn("During deserialization, ignoring metric named: {}. Unrecognized value type: {}", name, protoMsg.getMetric(i).getType(), ihte); } } // set the body if (protoMsg.hasBody()) { kuraMsg.setBody(protoMsg.getBody().toByteArray()); } return kuraMsg; } private KuraPosition buildFromProtoBuf(KuraPayloadProto.KuraPayload.KuraPosition protoPosition) { KuraPosition position = new KuraPosition(); if (protoPosition.hasLatitude()) { position.setLatitude(protoPosition.getLatitude()); } if (protoPosition.hasLongitude()) { position.setLongitude(protoPosition.getLongitude()); } if (protoPosition.hasAltitude()) { position.setAltitude(protoPosition.getAltitude()); } if (protoPosition.hasPrecision()) { position.setPrecision(protoPosition.getPrecision()); } if (protoPosition.hasHeading()) { position.setHeading(protoPosition.getHeading()); } if (protoPosition.hasSpeed()) { position.setSpeed(protoPosition.getSpeed()); } if (protoPosition.hasSatellites()) { position.setSatellites(protoPosition.getSatellites()); } if (protoPosition.hasStatus()) { position.setStatus(protoPosition.getStatus()); } if (protoPosition.hasTimestamp()) { position.setTimestamp(new Date(protoPosition.getTimestamp())); } return position; } private Object getProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric metric, KuraPayloadProto.KuraPayload.KuraMetric.ValueType type) throws KuraInvalidMetricTypeException { switch (type) { case DOUBLE: return metric.getDoubleValue(); case FLOAT: return metric.getFloatValue(); case INT64: return metric.getLongValue(); case INT32: return metric.getIntValue(); case BOOL: return metric.getBoolValue(); case STRING: return metric.getStringValue(); case BYTES: ByteString bs = metric.getBytesValue(); return bs.toByteArray(); default: throw new KuraInvalidMetricTypeException(type); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPayloadProtoBufEncoderImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.io.IOException; import java.util.Map; import org.eclipse.kura.KuraInvalidMetricTypeException; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraPosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; /** * Encodes an KuraPayload class using the Google ProtoBuf binary format. */ public class CloudPayloadProtoBufEncoderImpl implements CloudPayloadEncoder { private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufEncoderImpl.class); private final KuraPayload kuraPayload; public CloudPayloadProtoBufEncoderImpl(KuraPayload kuraPayload) { this.kuraPayload = kuraPayload; } /** * Conversion method to serialize an KuraPayload instance into a byte array. * * @return */ @Override public byte[] getBytes() throws IOException { // Build the message KuraPayloadProto.KuraPayload.Builder protoMsg = KuraPayloadProto.KuraPayload.newBuilder(); // set the timestamp if (this.kuraPayload.getTimestamp() != null) { protoMsg.setTimestamp(this.kuraPayload.getTimestamp().getTime()); } // set the position if (this.kuraPayload.getPosition() != null) { protoMsg.setPosition(buildPositionProtoBuf()); } // set the metrics for (final Map.Entry entry : this.kuraPayload.metrics().entrySet()) { final String name = entry.getKey(); final Object value = entry.getValue(); // build a metric try { KuraMetric.Builder metricB = KuraMetric.newBuilder(); metricB.setName(name); boolean result = setProtoKuraMetricValue(metricB, value); if (result) { // add it to the message protoMsg.addMetric(metricB); } } catch (KuraInvalidMetricTypeException e) { logger.error("During serialization, ignoring metric named: {}. Unrecognized value type: {}.", name, value != null ? value.getClass().getName() : ""); throw new RuntimeException(e); } } // set the body if (this.kuraPayload.getBody() != null) { protoMsg.setBody(ByteString.copyFrom(this.kuraPayload.getBody())); } return protoMsg.build().toByteArray(); } // // Helper methods to convert the KuraMetrics // private KuraPayloadProto.KuraPayload.KuraPosition buildPositionProtoBuf() { KuraPayloadProto.KuraPayload.KuraPosition.Builder protoPos = KuraPayloadProto.KuraPayload.KuraPosition .newBuilder(); KuraPosition position = this.kuraPayload.getPosition(); if (position.getLatitude() != null) { protoPos.setLatitude(position.getLatitude()); } if (position.getLongitude() != null) { protoPos.setLongitude(position.getLongitude()); } if (position.getAltitude() != null) { protoPos.setAltitude(position.getAltitude()); } if (position.getPrecision() != null) { protoPos.setPrecision(position.getPrecision()); } if (position.getHeading() != null) { protoPos.setHeading(position.getHeading()); } if (position.getSpeed() != null) { protoPos.setSpeed(position.getSpeed()); } if (position.getTimestamp() != null) { protoPos.setTimestamp(position.getTimestamp().getTime()); } if (position.getSatellites() != null) { protoPos.setSatellites(position.getSatellites()); } if (position.getStatus() != null) { protoPos.setStatus(position.getStatus()); } return protoPos.build(); } private static boolean setProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric.Builder metric, Object o) throws KuraInvalidMetricTypeException { if (o instanceof String) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.STRING); metric.setStringValue((String) o); } else if (o instanceof Double) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE); metric.setDoubleValue((Double) o); } else if (o instanceof Integer) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT32); metric.setIntValue((Integer) o); } else if (o instanceof Float) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.FLOAT); metric.setFloatValue((Float) o); } else if (o instanceof Long) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT64); metric.setLongValue((Long) o); } else if (o instanceof Boolean) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BOOL); metric.setBoolValue((Boolean) o); } else if (o instanceof byte[]) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BYTES); metric.setBytesValue(ByteString.copyFrom((byte[]) o)); } else if (o == null) { logger.warn("Received a metric with a null value!"); return false; } else { throw new KuraInvalidMetricTypeException(o.getClass().getName()); } return true; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudPublisherDeliveryListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; public interface CloudPublisherDeliveryListener { public void onMessageConfirmed(String messageId, String topic); } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudServiceLifecycleCertsPolicy.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; /** * This enum provides the necessary constants to denote the policy for the lifecycle messages. */ public enum CloudServiceLifecycleCertsPolicy { DISABLE_PUBLISHING("disable"), PUBLISH_BIRTH_CONNECT_ONLY("birth-connect"), PUBLISH_BIRTH_CONNECT_RECONNECT("birth-connect-reconnect"); private String birthPolicy; private CloudServiceLifecycleCertsPolicy(String policy) { this.birthPolicy = policy; } public String getValue() { return this.birthPolicy; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/CloudSubscriptionRecord.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; public class CloudSubscriptionRecord { private final String topic; private final int qos; private final CloudSubscriberListener subscriber; public CloudSubscriptionRecord(String topic, int qos, CloudSubscriberListener subscriber) { this.topic = topic; this.qos = qos; this.subscriber = subscriber; } public String getTopic() { return this.topic; } public int getQos() { return this.qos; } public CloudSubscriberListener getSubscriber() { return this.subscriber; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/ControlTopic.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; import org.eclipse.kura.message.KuraApplicationTopic; public class ControlTopic extends KuraApplicationTopic { private String fullTopic; private String[] topicParts; private String prefix; private String accountName; private String deviceId; private String req; private String reqId; public ControlTopic(String fullTopic) { this(fullTopic, MessageType.CONTROL.getTopicPrefix()); } public ControlTopic(String fullTopic, String controlPrefix) { this.fullTopic = fullTopic; if (fullTopic.compareTo("#") == 0) { return; } this.topicParts = fullTopic.split("/"); if (this.topicParts.length == 0) { return; } // prefix int index = 0; int offset = 0; // skip a slash if (this.topicParts[0].startsWith(controlPrefix)) { this.prefix = this.topicParts[index]; offset += this.prefix.length() + 1; index++; } // account name if (index < this.topicParts.length) { this.accountName = this.topicParts[index]; offset += this.accountName.length() + 1; index++; } // deviceId if (index < this.topicParts.length) { this.deviceId = this.topicParts[index]; offset += this.deviceId.length() + 1; index++; } // req // to skip? if (index < this.topicParts.length) { this.req = this.topicParts[index]; offset += this.req.length() + 1; index++; } // reqId if (index < this.topicParts.length) { this.reqId = this.topicParts[index]; offset += this.reqId.length() + 1; index++; } // applicationId if (index < this.topicParts.length) { this.applicationId = this.topicParts[index]; offset += this.applicationId.length() + 1; index++; } if (offset < this.fullTopic.length()) { this.applicationTopic = this.fullTopic.substring(offset); } } public String getFullTopic() { return this.fullTopic; } public String[] getTopicParts() { return this.topicParts; } public String getPrefix() { return this.prefix; } public String getAccountName() { return this.accountName; } public String getDeviceId() { return this.deviceId; } public String getReqId() { return this.reqId; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/LifeCyclePayloadBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import java.util.List; import java.util.Optional; import org.eclipse.kura.core.util.NetUtil; import org.eclipse.kura.message.KuraBirthPayload; import org.eclipse.kura.message.KuraBirthPayload.KuraBirthPayloadBuilder; import org.eclipse.kura.message.KuraDeviceProfile; import org.eclipse.kura.message.KuraDisconnectPayload; import org.eclipse.kura.message.KuraPosition; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetworkService; import org.eclipse.kura.position.PositionService; import org.eclipse.kura.system.SystemAdminService; import org.eclipse.kura.system.SystemService; import org.osgi.util.position.Position; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class to build lifecycle payload messages. */ public class LifeCyclePayloadBuilder { private static final String ERROR = "ERROR"; private static final Logger logger = LoggerFactory.getLogger(LifeCyclePayloadBuilder.class); private static final String UNKNOWN = "UNKNOWN"; private final CloudConnectionManagerImpl cloudConnectionManagerImpl; LifeCyclePayloadBuilder(CloudConnectionManagerImpl cloudConnectionManagerImpl) { this.cloudConnectionManagerImpl = cloudConnectionManagerImpl; } public KuraBirthPayload buildBirthPayload() { // build device profile KuraDeviceProfile deviceProfile = buildDeviceProfile(); // build accept encoding String acceptEncoding = buildAcceptEncoding(); // build device name CloudConnectionManagerOptions cso = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions(); String deviceName = cso.getDeviceDisplayName(); if (deviceName == null) { deviceName = this.cloudConnectionManagerImpl.getSystemService().getDeviceName(); } String payloadEncoding = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions().getPayloadEncoding() .name(); // build birth certificate KuraBirthPayloadBuilder birthPayloadBuilder = new KuraBirthPayloadBuilder(); birthPayloadBuilder.withUptime(deviceProfile.getUptime()).withDisplayName(deviceName) .withModelName(deviceProfile.getModelName()).withModelId(deviceProfile.getModelId()) .withPartNumber(deviceProfile.getPartNumber()).withSerialNumber(deviceProfile.getSerialNumber()) .withFirmwareVersion(deviceProfile.getFirmwareVersion()).withBiosVersion(deviceProfile.getBiosVersion()) .withCpuVersion(deviceProfile.getCpuVersion()).withOs(deviceProfile.getOs()) .withOsVersion(deviceProfile.getOsVersion()).withJvmName(deviceProfile.getJvmName()) .withJvmVersion(deviceProfile.getJvmVersion()).withJvmProfile(deviceProfile.getJvmProfile()) .withKuraVersion(deviceProfile.getApplicationFrameworkVersion()) .withConnectionInterface(deviceProfile.getConnectionInterface()) .withConnectionIp(deviceProfile.getConnectionIp()).withAcceptEncoding(acceptEncoding) .withAvailableProcessors(deviceProfile.getAvailableProcessors()) .withTotalMemory(deviceProfile.getTotalMemory()).withOsArch(deviceProfile.getOsArch()) .withOsgiFramework(deviceProfile.getOsgiFramework()) .withOsgiFrameworkVersion(deviceProfile.getOsgiFrameworkVersion()).withPayloadEncoding(payloadEncoding) .withJvmVendor(deviceProfile.getJvmVendor()).withJdkVendorVersion(deviceProfile.getJdkVendorVersion()); if (this.cloudConnectionManagerImpl.imei != null && this.cloudConnectionManagerImpl.imei.length() > 0 && !this.cloudConnectionManagerImpl.imei.equals(ERROR)) { birthPayloadBuilder.withModemImei(this.cloudConnectionManagerImpl.imei); } if (this.cloudConnectionManagerImpl.iccid != null && this.cloudConnectionManagerImpl.iccid.length() > 0 && !this.cloudConnectionManagerImpl.iccid.equals(ERROR)) { birthPayloadBuilder.withModemIccid(this.cloudConnectionManagerImpl.iccid); } if (this.cloudConnectionManagerImpl.imsi != null && this.cloudConnectionManagerImpl.imsi.length() > 0 && !this.cloudConnectionManagerImpl.imsi.equals(ERROR)) { birthPayloadBuilder.withModemImsi(this.cloudConnectionManagerImpl.imsi); } if (this.cloudConnectionManagerImpl.rssi != null && this.cloudConnectionManagerImpl.rssi.length() > 0) { birthPayloadBuilder.withModemRssi(this.cloudConnectionManagerImpl.rssi); } if (this.cloudConnectionManagerImpl.modemFwVer != null && this.cloudConnectionManagerImpl.modemFwVer.length() > 0 && !this.cloudConnectionManagerImpl.modemFwVer.equals(ERROR)) { birthPayloadBuilder.withModemFirmwareVersion(this.cloudConnectionManagerImpl.modemFwVer); } if (deviceProfile.getLatitude() != null && deviceProfile.getLongitude() != null) { KuraPosition kuraPosition = new KuraPosition(); kuraPosition.setLatitude(deviceProfile.getLatitude()); kuraPosition.setLongitude(deviceProfile.getLongitude()); kuraPosition.setAltitude(deviceProfile.getAltitude()); birthPayloadBuilder.withPosition(kuraPosition); } return birthPayloadBuilder.build(); } public KuraDisconnectPayload buildDisconnectPayload() { SystemService systemService = this.cloudConnectionManagerImpl.getSystemService(); SystemAdminService sysAdminService = this.cloudConnectionManagerImpl.getSystemAdminService(); CloudConnectionManagerOptions cloudOptions = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions(); // build device name String deviceName = cloudOptions.getDeviceDisplayName(); if (deviceName == null) { deviceName = systemService.getDeviceName(); } return new KuraDisconnectPayload(sysAdminService.getUptime(), deviceName); } public KuraDeviceProfile buildDeviceProfile() { SystemService systemService = this.cloudConnectionManagerImpl.getSystemService(); SystemAdminService sysAdminService = this.cloudConnectionManagerImpl.getSystemAdminService(); Optional networkService = this.cloudConnectionManagerImpl.getNetworkService(); Optional positionService = this.cloudConnectionManagerImpl.getPositionService(); // // get the network information StringBuilder sbConnectionIp = new StringBuilder(); StringBuilder sbConnectionInterface = new StringBuilder(); networkService.ifPresent(ns -> { try { List> nis = ns.getActiveNetworkInterfaces(); if (!nis.isEmpty()) { for (NetInterface ni : nis) { List nias = ni.getNetInterfaceAddresses(); if (nias != null && !nias.isEmpty()) { sbConnectionInterface.append(buildConnectionInterface(ni)).append(","); sbConnectionIp.append(buildConnectionIp(ni)).append(","); } } // Remove trailing comma sbConnectionIp.deleteCharAt(sbConnectionIp.length() - 1); sbConnectionInterface.deleteCharAt(sbConnectionInterface.length() - 1); } } catch (Exception se) { logger.warn("Error while getting ConnetionIP and ConnectionInterface", se); } }); String connectionIp = !sbConnectionIp.isEmpty() ? sbConnectionIp.toString() : UNKNOWN; String connectionInterface = !sbConnectionInterface.isEmpty() ? sbConnectionInterface.toString() : UNKNOWN; // // get the position information double latitude = 0.0; double longitude = 0.0; double altitude = 0.0; if (positionService.isPresent()) { Position position = positionService.get().getPosition(); if (position != null) { latitude = Math.toDegrees(position.getLatitude().getValue()); longitude = Math.toDegrees(position.getLongitude().getValue()); altitude = position.getAltitude().getValue(); } else { logger.warn("Unresolved PositionService reference."); } } return buildKuraDeviceProfile(systemService, sysAdminService, connectionIp, connectionInterface, latitude, longitude, altitude); } private KuraDeviceProfile buildKuraDeviceProfile(SystemService systemService, SystemAdminService sysAdminService, String connectionIp, String connectionInterface, double latitude, double longitude, double altitude) { KuraDeviceProfile kuraDeviceProfile = new KuraDeviceProfile(); kuraDeviceProfile.setUptime(sysAdminService.getUptime()); kuraDeviceProfile.setDisplayName(systemService.getDeviceName()); kuraDeviceProfile.setModelName(systemService.getModelName()); kuraDeviceProfile.setModelId(systemService.getModelId()); kuraDeviceProfile.setPartNumber(systemService.getPartNumber()); kuraDeviceProfile.setSerialNumber(systemService.getSerialNumber()); kuraDeviceProfile.setFirmwareVersion(systemService.getFirmwareVersion()); kuraDeviceProfile.setBiosVersion(systemService.getBiosVersion()); kuraDeviceProfile.setOs(systemService.getOsName()); kuraDeviceProfile.setOsVersion(systemService.getOsVersion()); kuraDeviceProfile.setCpuVersion(systemService.getCpuVersion()); kuraDeviceProfile.setJvmName(systemService.getJavaVmName()); kuraDeviceProfile.setJvmVersion(systemService.getJavaVmVersion() + " " + systemService.getJavaVmInfo()); kuraDeviceProfile.setJvmProfile(systemService.getJavaVendor() + " " + systemService.getJavaVersion()); kuraDeviceProfile.setApplicationFramework(KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK); kuraDeviceProfile.setApplicationFrameworkVersion(systemService.getKuraVersion()); kuraDeviceProfile.setConnectionInterface(connectionInterface); kuraDeviceProfile.setConnectionIp(connectionIp); kuraDeviceProfile.setLatitude(latitude); kuraDeviceProfile.setLongitude(longitude); kuraDeviceProfile.setAltitude(altitude); kuraDeviceProfile.setAvailableProcessors(String.valueOf(systemService.getNumberOfProcessors())); kuraDeviceProfile.setTotalMemory(String.valueOf(systemService.getTotalMemory())); kuraDeviceProfile.setOsArch(systemService.getOsArch()); kuraDeviceProfile.setOsgiFramework(systemService.getOsgiFwName()); kuraDeviceProfile.setOsgiFrameworkVersion(systemService.getOsgiFwVersion()); kuraDeviceProfile.setJvmVendor(systemService.getJavaVmVendor()); kuraDeviceProfile.setJdkVendorVersion(systemService.getJdkVendorVersion()); return kuraDeviceProfile; } private String buildConnectionIp(NetInterface ni) { String connectionIp = UNKNOWN; List nias = ni.getNetInterfaceAddresses(); if (nias != null && !nias.isEmpty() && nias.get(0).getAddress() != null) { connectionIp = nias.get(0).getAddress().getHostAddress(); } return connectionIp; } private String buildConnectionInterface(NetInterface ni) { StringBuilder sb = new StringBuilder(); sb.append(ni.getName()).append(" (").append(NetUtil.hardwareAddressToString(ni.getHardwareAddress())) .append(")"); return sb.toString(); } private String buildAcceptEncoding() { String acceptEncoding = ""; CloudConnectionManagerOptions options = this.cloudConnectionManagerImpl.getCloudConnectionManagerOptions(); if (options.getEncodeGzip()) { acceptEncoding = "gzip"; } return acceptEncoding; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/LifecycleMessage.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; import org.eclipse.kura.message.KuraPayload; public class LifecycleMessage { private StringBuilder topicBuilder; private CloudConnectionManagerOptions options; private LifeCyclePayloadBuilder payloadBuilder; private KuraPayload payload; public LifecycleMessage(CloudConnectionManagerOptions options, CloudConnectionManagerImpl cloudServiceImpl) { this.options = options; this.topicBuilder = new StringBuilder(MessageType.EVENT.getTopicPrefix()); this.topicBuilder.append(this.options.getTopicSeparator()).append(this.options.getTopicSeparator()) .append(this.options.getTopicSeparator()); this.payloadBuilder = new LifeCyclePayloadBuilder(cloudServiceImpl); } public LifecycleMessage asBirthCertificateMessage() { this.topicBuilder.append(this.options.getTopicBirthSuffix()); this.payload = this.payloadBuilder.buildBirthPayload(); return this; } public LifecycleMessage asDisconnectCertificateMessage() { this.topicBuilder.append(this.options.getTopicDisconnectSuffix()); this.payload = this.payloadBuilder.buildDisconnectPayload(); return this; } public String getTopic() { return this.topicBuilder.toString(); } public KuraPayload getPayload() { return this.payload; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/MessageHandlerCallable.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud; import static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.NOTIFICATION_PUBLISHER_PID; import static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY; import java.io.PrintWriter; import java.io.StringWriter; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.audit.AuditConstants; import org.eclipse.kura.audit.AuditContext; import org.eclipse.kura.audit.AuditContext.Scope; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerContext; import org.eclipse.kura.data.DataService; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; import org.eclipse.kura.message.KuraPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageHandlerCallable implements Callable { private static final Logger auditLogger = LoggerFactory.getLogger("AuditLogger"); private static final Logger logger = LoggerFactory.getLogger(MessageHandlerCallable.class); private static final Pattern RESOURCES_DELIM = Pattern.compile("/"); public static final String METRIC_REQUEST_ID = "request.id"; public static final String REQUESTER_CLIENT_ID = "requester.client.id"; public static final String METRIC_RESPONSE_CODE = "response.code"; public static final String METRIC_EXCEPTION_MSG = "response.exception.message"; public static final String METRIC_EXCEPTION_STACK = "response.exception.stack"; public static final int RESPONSE_CODE_OK = 200; public static final int RESPONSE_CODE_BAD_REQUEST = 400; public static final int RESPONSE_CODE_NOTFOUND = 404; public static final int RESPONSE_CODE_ERROR = 500; protected static final int DFLT_PUB_QOS = 0; protected static final boolean DFLT_RETAIN = false; protected static final int DFLT_PRIORITY = 1; private final RequestHandler cloudApp; private final String appTopic; private final KuraPayload kuraMessage; private final CloudConnectionManagerImpl cloudConnectionManager; private final RequestHandlerContext requestHandlerContext; public MessageHandlerCallable(RequestHandler cloudApp, String appTopic, KuraPayload msg, CloudConnectionManagerImpl cloudConnectionManager) { super(); this.cloudApp = cloudApp; this.appTopic = appTopic; this.kuraMessage = msg; this.cloudConnectionManager = cloudConnectionManager; String notificationPublisherPid = null; // TODO: this.cloudConnectionManager.getNotificationPublisherPid(); CloudNotificationPublisher notificationPublisher = null; // TODO: // this.cloudConnectionManager.getNotificationPublisher(); Map contextProperties = new HashMap<>(); contextProperties.put(NOTIFICATION_PUBLISHER_PID.name(), notificationPublisherPid); this.requestHandlerContext = new RequestHandlerContext(notificationPublisher, contextProperties); } @Override public Void call() throws Exception { logger.debug("Control Arrived on topic: {}", this.appTopic); String requestId = (String) this.kuraMessage.getMetric(METRIC_REQUEST_ID); if (requestId == null) { if(logger.isDebugEnabled()) { logger.debug("Request Id is null"); } throw new ParseException("Not a valid request payload", 0); } // Prepare the default response KuraPayload reqPayload = this.kuraMessage; KuraMessage response; final Map auditProperties = new HashMap<>(); auditProperties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), "EclipseIoTCloudConnectionService"); auditProperties.put("cloud.app.topic", appTopic); auditProperties.put("cloud.connection.pid", cloudConnectionManager.getOwnPid()); try (final Scope scope = AuditContext.openScope(new AuditContext(auditProperties))) { try { Iterator resources = RESOURCES_DELIM.splitAsStream(this.appTopic).iterator(); if (!resources.hasNext()) { throw new IllegalArgumentException(); } String method = resources.next(); Map reqResources = getMessageResources(resources); KuraMessage reqMessage = new KuraMessage(reqPayload, reqResources); switch (method) { case "GET": logger.debug("Handling GET request topic: {}", this.appTopic); response = this.cloudApp.doGet(this.requestHandlerContext, reqMessage); break; case "PUT": logger.debug("Handling PUT request topic: {}", this.appTopic); response = this.cloudApp.doPut(this.requestHandlerContext, reqMessage); break; case "POST": logger.debug("Handling POST request topic: {}", this.appTopic); response = this.cloudApp.doPost(this.requestHandlerContext, reqMessage); break; case "DEL": logger.debug("Handling DEL request topic: {}", this.appTopic); response = this.cloudApp.doDel(this.requestHandlerContext, reqMessage); break; case "EXEC": logger.debug("Handling EXEC request topic: {}", this.appTopic); response = this.cloudApp.doExec(this.requestHandlerContext, reqMessage); break; default: logger.error("Bad request topic: {}", this.appTopic); KuraPayload payload = new KuraPayload(); response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); break; } } catch (IllegalArgumentException e) { logger.error("Bad request topic: {}", this.appTopic); KuraPayload payload = new KuraPayload(); response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); } catch (KuraException e) { logger.error("Error handling request topic: {}", this.appTopic, e); response = manageException(e); } final Object responseCode = response.getPayload().getMetric(METRIC_RESPONSE_CODE); final boolean isSuccessful = responseCode instanceof Integer && ((Integer) responseCode) / 200 == 1; if (isSuccessful) { auditLogger.info("{} CloudCall - Success - Execute RequestHandler call", AuditContext.currentOrInternal()); } else { auditLogger.warn("{} CloudCall - Failure - Execute RequestHandler call", AuditContext.currentOrInternal()); } buildResponseMessage(requestId, response); } return null; } private void buildResponseMessage(String requestId, KuraMessage response) { try { response.getPayload().setTimestamp(new Date()); DataService dataService = this.cloudConnectionManager.getDataService(); String fullTopic = encodeTopic(requestId, String.valueOf(response.getPayload().getMetric(METRIC_RESPONSE_CODE))); byte[] appPayload = this.cloudConnectionManager.encodePayload(response.getPayload()); dataService.publish(fullTopic, appPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY); } catch (KuraException e) { logger.error("Error publishing response for topic: {}\n{}", this.appTopic, e); } } private KuraMessage manageException(KuraException e) { KuraMessage message; KuraPayload payload = new KuraPayload(); setException(payload, e); if (e.getCode().equals(KuraErrorCode.BAD_REQUEST)) { message = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); } else if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) { message = setResponseCode(payload, RESPONSE_CODE_NOTFOUND); } else { message = setResponseCode(payload, RESPONSE_CODE_ERROR); } return message; } private Map getMessageResources(Iterator iter) { List resourcesList = new ArrayList<>(); while (iter.hasNext()) { resourcesList.add(iter.next()); } Map properties = new HashMap<>(); properties.put(ARGS_KEY.value(), resourcesList); return properties; } public KuraMessage setResponseCode(KuraPayload payload, int responseCode) { payload.addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode)); return new KuraMessage(payload); } public void setException(KuraPayload payload, Throwable t) { if (t != null) { payload.addMetric(METRIC_EXCEPTION_MSG, t.getMessage()); payload.addMetric(METRIC_EXCEPTION_STACK, stackTraceAsString(t)); } } private String stackTraceAsString(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } private String encodeTopic(String requestId, String responseCode) { CloudConnectionManagerOptions options = this.cloudConnectionManager.getCloudConnectionManagerOptions(); String topicSeparator = options.getTopicSeparator(); StringBuilder sb = new StringBuilder(); // fixed response topic subsection sb.append(MessageType.CONTROL.getTopicPrefix()).append(topicSeparator).append(topicSeparator) .append(topicSeparator).append("res"); // variable response topic part sb.append(topicSeparator).append(requestId).append(topicSeparator).append(responseCode); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/factory/DefaultCloudConnectionFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.factory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.DataTransportService; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentConstants; /** * The Kura default {@link CloudConnectionFactory} implements a three layer stack architecture. * Each layer is an OSGi Declarative Services Factory Component and provides a service as follows: * * * * * * * * * * * * * * * * * * * * * * *
Factory PIDService interface
org.eclipse.kura.cloud.CloudService{@link DataService}
org.eclipse.kura.data.DataService{@link DataService}
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport{@link DataTransportService}
*
* When a new CloudService is created the factory creates also a DataService and a DataTransportService. * Since the pid parameter of {@link #createConfiguration(String)} only specifies the PID of * the CloudService layer, a convention is needed to derive the PIDs of the lower layers. *
*
* The default stack instance is special. * For backward compatibility the PIDs of the default stack must be as follows: * * * * * * * * * * * * * * * * * * * * * * *
PID (kura.service.pid)Factory PID
org.eclipse.kura.cloud.CloudServiceorg.eclipse.kura.cloud.CloudService
org.eclipse.kura.data.DataServiceorg.eclipse.kura.data.DataService
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
*
* * For other stack instances the convention used to generate the PIDs for the lower layers is * to use the sub string in the CloudService PID starting after the first occurrence of the '-' character and append * the sub string to the PIDs of the default stack above, for example: * * * * * * * * * * * * * * * * * * * * * * *
PID (kura.service.pid)Factory PID
org.eclipse.kura.cloud.CloudService-2org.eclipse.kura.cloud.CloudService
org.eclipse.kura.data.DataService-2org.eclipse.kura.data.DataService
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
*
* The (configuration of) layer instances of each stack are persisted to Kura snapshot and * recreated at every Kura start. * On startup every stack must be properly reassembled with the right layer instances. *
* This can be achieved using a standard OSGi Declarative Services magic property set in a layer configuration * specifying the layer dependency on a specific PID of its next lower layer. * The following example shows this selective dependency mechanism for the DataService and MqttDataTransport services. *
* The DataService component definition specifies a dependency on a DataTransportService as follows: * *
 * <reference name="DataTransportService"
 *              bind="setDataTransportService"
 *              unbind="unsetDataTransportService"
 *              cardinality="1..1"
 *              policy="static"
 *              interface="org.eclipse.kura.data.DataTransportService"/>
 * 
* *
* The DataService with PID org.eclipse.kura.data.DataService-2 needs to be activated * only when its dependency on a specific DataTransportService with * PID org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2 is satisfied. *
* The OSGi Declarative Services specification provides a magic <reference name>.target * property that can be set at runtime to specify a selective dependency. *
* In the above example the org.eclipse.kura.data.DataService-2 component instance will have a * DataTransportService.target property set to the value: * *
 * (kura.service.pid = org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport - 2)
 * 
* *
*/ public class DefaultCloudConnectionFactory implements CloudConnectionFactory { private static final String FACTORY_PID = "org.eclipse.kura.cloud.mqtt.eclipseiot.internal.cloud.factory.DefaultCloudServiceFactory"; // The following constants must match the factory component definitions private static final String CLOUD_SERVICE_FACTORY_PID = "org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager"; private static final String DATA_SERVICE_FACTORY_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String CLOUD_SERVICE_PID = "org.eclipse.kura.cloudconnection.eclipseiot.mqtt.ConnectionManager"; private static final String DATA_SERVICE_PID = "org.eclipse.kura.cloudconnection.eclipseiot.mqtt.DataService"; private static final String DATA_TRANSPORT_SERVICE_PID = "org.eclipse.kura.cloudconnection.eclipseiot.mqtt.MqttDataTransport"; private static final String DATA_SERVICE_REFERENCE_NAME = "DataService"; private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = "DataTransportService"; private static final String REFERENCE_TARGET_VALUE_FORMAT = "(" + ConfigurationService.KURA_SERVICE_PID + "=%s)"; private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern.compile( "^org\\.eclipse\\.kura\\.cloudconnection\\.eclipseiot\\.mqtt\\.ConnectionManager(-[a-zA-Z0-9]+)?$"); private ConfigurationService configurationService; protected void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } protected void unsetConfigurationService(ConfigurationService configurationService) { if (configurationService == this.configurationService) { this.configurationService = null; } } @Override public String getFactoryPid() { return CLOUD_SERVICE_FACTORY_PID; } @Override public void createConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } // create the CloudService layer and set the selective dependency on the DataService PID Map cloudServiceProperties = new HashMap<>(); String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid)); cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID); this.configurationService.createFactoryConfiguration(CLOUD_SERVICE_FACTORY_PID, pid, cloudServiceProperties, false); // create the DataService layer and set the selective dependency on the DataTransportService PID Map dataServiceProperties = new HashMap<>(); name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid)); this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid, dataServiceProperties, false); // create the DataTransportService layer and take a snapshot this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID, dataTransportServicePid, null, true); } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public void deleteConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } this.configurationService.deleteFactoryConfiguration(pid, false); this.configurationService.deleteFactoryConfiguration(dataServicePid, false); this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true); } } @Override public List getStackComponentsPids(String pid) throws KuraException { List componentPids = new ArrayList<>(); String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } componentPids.add(pid); componentPids.add(dataServicePid); componentPids.add(dataTransportServicePid); return componentPids; } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public Set getManagedCloudConnectionPids() throws KuraException { final BundleContext context = FrameworkUtil.getBundle(DefaultCloudConnectionFactory.class).getBundleContext(); try { return context.getServiceReferences(CloudConnectionManager.class, null).stream().filter(ref -> { final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID); if (!(kuraServicePid instanceof String)) { return false; } return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches() && FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID)); }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet()); } catch (InvalidSyntaxException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/publisher/CloudPublisherImpl.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher; import static java.util.Objects.nonNull; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.FULL_TOPIC; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.PRIORITY; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.QOS; import static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageConstants.RETAIN; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerImpl; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudConnectionManagerOptions; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.CloudPublisherDeliveryListener; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudPublisherImpl implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudPublisherDeliveryListener { private final class CloudConnectionManagerTrackerCustomizer implements ServiceTrackerCustomizer { @Override public CloudConnectionManager addingService(final ServiceReference reference) { CloudConnectionManager tempCloudService = CloudPublisherImpl.this.bundleContext.getService(reference); if (tempCloudService instanceof CloudConnectionManagerImpl) { CloudPublisherImpl.this.cloudConnectionImpl = (CloudConnectionManagerImpl) tempCloudService; CloudPublisherImpl.this.cloudConnectionImpl.registerCloudConnectionListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudConnectionImpl .registerCloudPublisherDeliveryListener(CloudPublisherImpl.this); return tempCloudService; } else { CloudPublisherImpl.this.bundleContext.ungetService(reference); } return null; } @Override public void removedService(final ServiceReference reference, final CloudConnectionManager service) { CloudPublisherImpl.this.cloudConnectionImpl.unregisterCloudConnectionListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudConnectionImpl .unregisterCloudPublisherDeliveryListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudConnectionImpl = null; } @Override public void modifiedService(ServiceReference reference, CloudConnectionManager service) { // Not needed } } private static final Logger logger = LoggerFactory.getLogger(CloudPublisherImpl.class); private static final String TOPIC_PATTERN_STRING = "\\$([^\\s/]+)"; private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING); private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private final Set cloudDeliveryListeners = new CopyOnWriteArraySet<>(); private ServiceTrackerCustomizer cloudConnectionManagerTrackerCustomizer; private ServiceTracker cloudConnectionManagerTracker; private CloudPublisherOptions cloudPublisherOptions; private CloudConnectionManagerImpl cloudConnectionImpl; private BundleContext bundleContext; private final ExecutorService worker = Executors.newCachedThreadPool(); protected void activate(ComponentContext componentContext, Map properties) { logger.debug("Activating Cloud Publisher..."); this.bundleContext = componentContext.getBundleContext(); this.cloudPublisherOptions = new CloudPublisherOptions(properties); this.cloudConnectionManagerTrackerCustomizer = new CloudConnectionManagerTrackerCustomizer(); initCloudConnectionManagerTracking(); logger.debug("Activating Cloud Publisher... Done"); } public void updated(Map properties) { logger.debug("Updating Cloud Publisher..."); this.cloudPublisherOptions = new CloudPublisherOptions(properties); if (nonNull(this.cloudConnectionManagerTracker)) { this.cloudConnectionManagerTracker.close(); } initCloudConnectionManagerTracking(); logger.debug("Updating Cloud Publisher... Done"); } protected void deactivate(ComponentContext componentContext) { logger.debug("Deactivating Cloud Publisher..."); if (nonNull(this.cloudConnectionManagerTracker)) { this.cloudConnectionManagerTracker.close(); } this.worker.shutdown(); logger.debug("Deactivating Cloud Publisher... Done"); } @Override public String publish(KuraMessage message) throws KuraException { if (this.cloudConnectionImpl == null) { logger.info("Null cloud service"); throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "The Cloud Service is null."); } if (message == null) { logger.warn("Received null message!"); throw new IllegalArgumentException(); } MessageType messageType = this.cloudPublisherOptions.getMessageType(); String fullTopic = encodeFullTopic(message, messageType.getTopicPrefix()); int qos = messageType.getQos(); boolean retain = false; int priority = messageType.getPriority(); Map publishMessageProps = new HashMap<>(); publishMessageProps.put(FULL_TOPIC.name(), fullTopic); publishMessageProps.put(QOS.name(), qos); publishMessageProps.put(RETAIN.name(), retain); publishMessageProps.put(PRIORITY.name(), priority); KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps); return this.cloudConnectionImpl.publish(publishMessage); } private String encodeFullTopic(KuraMessage message, String topicPrefix) { String fullTopic = encodeTopic(topicPrefix, this.cloudPublisherOptions.getSemanticTopic()); return fillTopicPlaceholders(fullTopic, message); } private void initCloudConnectionManagerTracking() { String selectedCloudServicePid = this.cloudPublisherOptions.getCloudServicePid(); String filterString = String.format("(&(%s=%s)(kura.service.pid=%s))", Constants.OBJECTCLASS, CloudConnectionManager.class.getName(), selectedCloudServicePid); Filter filter = null; try { filter = this.bundleContext.createFilter(filterString); } catch (InvalidSyntaxException e) { logger.error("Filter setup exception ", e); } this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter, this.cloudConnectionManagerTrackerCustomizer); this.cloudConnectionManagerTracker.open(); } private String encodeTopic(String topicPrefix, String semanticTopic) { CloudConnectionManagerOptions options = this.cloudConnectionImpl.getCloudConnectionManagerOptions(); String topicSeparator = options.getTopicSeparator(); StringBuilder sb = new StringBuilder(); sb.append(topicPrefix).append(topicSeparator).append(topicSeparator); if (semanticTopic != null && !semanticTopic.isEmpty()) { sb.append(topicSeparator).append(semanticTopic); } return sb.toString(); } private String fillTopicPlaceholders(String semanticTopic, KuraMessage message) { Matcher matcher = TOPIC_PATTERN.matcher(semanticTopic); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { Map properties = message.getProperties(); if (properties.containsKey(matcher.group(1))) { String replacement = matcher.group(0); Object value = properties.get(matcher.group(1)); if (replacement != null) { matcher.appendReplacement(buffer, value.toString()); } } } matcher.appendTail(buffer); return buffer.toString(); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected)); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost)); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished)); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } @Override public void onMessageConfirmed(String messageId, String topic) { CloudConnectionManagerOptions options = this.cloudConnectionImpl.getCloudConnectionManagerOptions(); String topicSeparator = options.getTopicSeparator(); String[] semanticTopicElements = this.cloudPublisherOptions.getSemanticTopic().split(topicSeparator); int index = getSemanticTopicComparisonOffset(semanticTopicElements); String semanticTopicComparisonElement = semanticTopicElements[index]; String[] messageSemanticTopicElements = getMessageSemanticTopicElements(topic, topicSeparator, semanticTopicComparisonElement); if (messageSemanticTopicElements.length == 0) { return; } index = 0; for (String semanticTopicElement : semanticTopicElements) { if (!semanticTopicElement.equals(messageSemanticTopicElements[index])) { return; } index++; } this.cloudDeliveryListeners .forEach(deliveryListener -> this.worker.execute(() -> deliveryListener.onMessageConfirmed(messageId))); } private String[] getMessageSemanticTopicElements(String topic, String topicSeparator, String semanticTopicComparisonElement) { int messagePostfixTopicOffset = topic.indexOf(semanticTopicComparisonElement); if (messagePostfixTopicOffset >= 0) { String messagePostfixTopic = topic.substring(messagePostfixTopicOffset, topic.length()); return messagePostfixTopic.split(topicSeparator); } return new String[0]; } private int getSemanticTopicComparisonOffset(String[] semanticTopicElements) { int index = 0; for (String semanticTopicElement : semanticTopicElements) { if (semanticTopicElement.startsWith("$")) { index++; } else { break; } } return index; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/cloud/publisher/CloudPublisherOptions.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.cloud.publisher; import java.util.Map; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.MessageType; public class CloudPublisherOptions { private static final Property PROPERTY_CLOUD_SERVICE_PID = new Property<>( CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), "org.eclipse.kura.cloud.mqtt.eclipseiot.CloudService"); private static final Property PROPERTY_SEMANTIC_TOPIC = new Property<>("semantic.topic", "W1/A1/$assetName"); private static final Property PROPERTY_QOS = new Property<>("qos", 0); private static final Property PROPERTY_MESSAGE_TYPE = new Property<>("message.type", "telemetryQos0"); private final String cloudServicePid; private final String semanticTopic; private final int qos; private final String messageType; public CloudPublisherOptions(final Map properties) { this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties); this.semanticTopic = PROPERTY_SEMANTIC_TOPIC.get(properties); this.qos = PROPERTY_QOS.get(properties); this.messageType = PROPERTY_MESSAGE_TYPE.get(properties); } public String getCloudServicePid() { return this.cloudServicePid; } public String getSemanticTopic() { return this.semanticTopic; } public int getQos() { return this.qos; } public MessageType getMessageType() { return MessageType.fromValue(this.messageType); } private static final class Property { private final String key; private final T defaultValue; public Property(final String key, final T defaultValue) { this.key = key; this.defaultValue = defaultValue; } @SuppressWarnings("unchecked") public T get(final Map properties) { final Object value = properties.get(this.key); if (this.defaultValue.getClass().isInstance(value)) { return (T) value; } return this.defaultValue; } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/MessageConstants.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message; public enum MessageConstants { FULL_TOPIC, QOS, RETAIN, PRIORITY, CONTROL; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/MessageType.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message; public enum MessageType { TELEMETRY_QOS_0("telemetryQos0", 0, 7, "t"), TELEMETRY_QOS_1("telemetryQos1", 1, 7, "t"), EVENT("event", 1, 5, "e"), ALERT("alert", 1, 2, "a"), CONTROL("control", 0, 2, "c"); private String type; private int qos; private int priority; private String topicPrefix; private MessageType(String type, int qos, int priority, String topicPrefix) { this.type = type; this.qos = qos; this.priority = priority; this.topicPrefix = topicPrefix; } public String getType() { return this.type; } public int getQos() { return this.qos; } public int getPriority() { return this.priority; } public String getTopicPrefix() { return this.topicPrefix; } public static MessageType fromValue(String v) { for (MessageType mt : MessageType.values()) { if (mt.type.equals(v)) { return mt; } } throw new IllegalArgumentException(v); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/java/org/eclipse/kura/internal/cloudconnection/eclipseiot/mqtt/message/protobuf/KuraPayloadProto.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: kurapayload.proto // Protobuf Java Version: 4.29.3 package org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf; public final class KuraPayloadProto { private KuraPayloadProto() {} static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPayloadProto.class.getName()); } public static void registerAllExtensions( com.google.protobuf.ExtensionRegistryLite registry) { } public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { registerAllExtensions( (com.google.protobuf.ExtensionRegistryLite) registry); } public interface KuraPayloadOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload) com.google.protobuf.GeneratedMessage. ExtendableMessageOrBuilder { /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ boolean hasTimestamp(); /** * optional int64 timestamp = 1; * @return The timestamp. */ long getTimestamp(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ boolean hasPosition(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ java.util.List getMetricList(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ int getMetricCount(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ java.util.List getMetricOrBuilderList(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index); /** * optional bytes body = 5001; * @return Whether the body field is set. */ boolean hasBody(); /** * optional bytes body = 5001; * @return The body. */ com.google.protobuf.ByteString getBody(); } /** * Protobuf type {@code kuradatatypes.KuraPayload} */ public static final class KuraPayload extends com.google.protobuf.GeneratedMessage.ExtendableMessage< KuraPayload> implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload) KuraPayloadOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPayload.class.getName()); } // Use KuraPayload.newBuilder() to construct. private KuraPayload(com.google.protobuf.GeneratedMessage.ExtendableBuilder builder) { super(builder); } private KuraPayload() { metric_ = java.util.Collections.emptyList(); body_ = com.google.protobuf.ByteString.EMPTY; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class); } public interface KuraMetricOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraMetric) com.google.protobuf.MessageOrBuilder { /** * required string name = 1; * @return Whether the name field is set. */ boolean hasName(); /** * required string name = 1; * @return The name. */ java.lang.String getName(); /** * required string name = 1; * @return The bytes for name. */ com.google.protobuf.ByteString getNameBytes(); /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ boolean hasType(); /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType(); /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ boolean hasDoubleValue(); /** * optional double double_value = 3; * @return The doubleValue. */ double getDoubleValue(); /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ boolean hasFloatValue(); /** * optional float float_value = 4; * @return The floatValue. */ float getFloatValue(); /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ boolean hasLongValue(); /** * optional int64 long_value = 5; * @return The longValue. */ long getLongValue(); /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ boolean hasIntValue(); /** * optional int32 int_value = 6; * @return The intValue. */ int getIntValue(); /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ boolean hasBoolValue(); /** * optional bool bool_value = 7; * @return The boolValue. */ boolean getBoolValue(); /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ boolean hasStringValue(); /** * optional string string_value = 8; * @return The stringValue. */ java.lang.String getStringValue(); /** * optional string string_value = 8; * @return The bytes for stringValue. */ com.google.protobuf.ByteString getStringValueBytes(); /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ boolean hasBytesValue(); /** * optional bytes bytes_value = 9; * @return The bytesValue. */ com.google.protobuf.ByteString getBytesValue(); } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric} */ public static final class KuraMetric extends com.google.protobuf.GeneratedMessage implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraMetric) KuraMetricOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraMetric.class.getName()); } // Use KuraMetric.newBuilder() to construct. private KuraMetric(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } private KuraMetric() { name_ = ""; type_ = 0; stringValue_ = ""; bytesValue_ = com.google.protobuf.ByteString.EMPTY; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class); } /** * Protobuf enum {@code kuradatatypes.KuraPayload.KuraMetric.ValueType} */ public enum ValueType implements com.google.protobuf.ProtocolMessageEnum { /** * DOUBLE = 0; */ DOUBLE(0), /** * FLOAT = 1; */ FLOAT(1), /** * INT64 = 2; */ INT64(2), /** * INT32 = 3; */ INT32(3), /** * BOOL = 4; */ BOOL(4), /** * STRING = 5; */ STRING(5), /** * BYTES = 6; */ BYTES(6), ; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", ValueType.class.getName()); } /** * DOUBLE = 0; */ public static final int DOUBLE_VALUE = 0; /** * FLOAT = 1; */ public static final int FLOAT_VALUE = 1; /** * INT64 = 2; */ public static final int INT64_VALUE = 2; /** * INT32 = 3; */ public static final int INT32_VALUE = 3; /** * BOOL = 4; */ public static final int BOOL_VALUE = 4; /** * STRING = 5; */ public static final int STRING_VALUE = 5; /** * BYTES = 6; */ public static final int BYTES_VALUE = 6; public final int getNumber() { return value; } /** * @param value The numeric wire value of the corresponding enum entry. * @return The enum associated with the given numeric wire value. * @deprecated Use {@link #forNumber(int)} instead. */ @java.lang.Deprecated public static ValueType valueOf(int value) { return forNumber(value); } /** * @param value The numeric wire value of the corresponding enum entry. * @return The enum associated with the given numeric wire value. */ public static ValueType forNumber(int value) { switch (value) { case 0: return DOUBLE; case 1: return FLOAT; case 2: return INT64; case 3: return INT32; case 4: return BOOL; case 5: return STRING; case 6: return BYTES; default: return null; } } public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { return internalValueMap; } private static final com.google.protobuf.Internal.EnumLiteMap< ValueType> internalValueMap = new com.google.protobuf.Internal.EnumLiteMap() { public ValueType findValueByNumber(int number) { return ValueType.forNumber(number); } }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { return getDescriptor().getValues().get(ordinal()); } public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { return getDescriptor(); } public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDescriptor().getEnumTypes().get(0); } private static final ValueType[] VALUES = values(); public static ValueType valueOf( com.google.protobuf.Descriptors.EnumValueDescriptor desc) { if (desc.getType() != getDescriptor()) { throw new java.lang.IllegalArgumentException( "EnumValueDescriptor is not for this type."); } return VALUES[desc.getIndex()]; } private final int value; private ValueType(int value) { this.value = value; } // @@protoc_insertion_point(enum_scope:kuradatatypes.KuraPayload.KuraMetric.ValueType) } private int bitField0_; public static final int NAME_FIELD_NUMBER = 1; @SuppressWarnings("serial") private volatile java.lang.Object name_ = ""; /** * required string name = 1; * @return Whether the name field is set. */ @java.lang.Override public boolean hasName() { return ((bitField0_ & 0x00000001) != 0); } /** * required string name = 1; * @return The name. */ @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { name_ = s; } return s; } } /** * required string name = 1; * @return The bytes for name. */ @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } public static final int TYPE_FIELD_NUMBER = 2; private int type_ = 0; /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ @java.lang.Override public boolean hasType() { return ((bitField0_ & 0x00000002) != 0); } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_); return result == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result; } public static final int DOUBLE_VALUE_FIELD_NUMBER = 3; private double doubleValue_ = 0D; /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ @java.lang.Override public boolean hasDoubleValue() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double double_value = 3; * @return The doubleValue. */ @java.lang.Override public double getDoubleValue() { return doubleValue_; } public static final int FLOAT_VALUE_FIELD_NUMBER = 4; private float floatValue_ = 0F; /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ @java.lang.Override public boolean hasFloatValue() { return ((bitField0_ & 0x00000008) != 0); } /** * optional float float_value = 4; * @return The floatValue. */ @java.lang.Override public float getFloatValue() { return floatValue_; } public static final int LONG_VALUE_FIELD_NUMBER = 5; private long longValue_ = 0L; /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ @java.lang.Override public boolean hasLongValue() { return ((bitField0_ & 0x00000010) != 0); } /** * optional int64 long_value = 5; * @return The longValue. */ @java.lang.Override public long getLongValue() { return longValue_; } public static final int INT_VALUE_FIELD_NUMBER = 6; private int intValue_ = 0; /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ @java.lang.Override public boolean hasIntValue() { return ((bitField0_ & 0x00000020) != 0); } /** * optional int32 int_value = 6; * @return The intValue. */ @java.lang.Override public int getIntValue() { return intValue_; } public static final int BOOL_VALUE_FIELD_NUMBER = 7; private boolean boolValue_ = false; /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ @java.lang.Override public boolean hasBoolValue() { return ((bitField0_ & 0x00000040) != 0); } /** * optional bool bool_value = 7; * @return The boolValue. */ @java.lang.Override public boolean getBoolValue() { return boolValue_; } public static final int STRING_VALUE_FIELD_NUMBER = 8; @SuppressWarnings("serial") private volatile java.lang.Object stringValue_ = ""; /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ @java.lang.Override public boolean hasStringValue() { return ((bitField0_ & 0x00000080) != 0); } /** * optional string string_value = 8; * @return The stringValue. */ @java.lang.Override public java.lang.String getStringValue() { java.lang.Object ref = stringValue_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { stringValue_ = s; } return s; } } /** * optional string string_value = 8; * @return The bytes for stringValue. */ @java.lang.Override public com.google.protobuf.ByteString getStringValueBytes() { java.lang.Object ref = stringValue_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); stringValue_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } public static final int BYTES_VALUE_FIELD_NUMBER = 9; private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ @java.lang.Override public boolean hasBytesValue() { return ((bitField0_ & 0x00000100) != 0); } /** * optional bytes bytes_value = 9; * @return The bytesValue. */ @java.lang.Override public com.google.protobuf.ByteString getBytesValue() { return bytesValue_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (!hasName()) { memoizedIsInitialized = 0; return false; } if (!hasType()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (((bitField0_ & 0x00000001) != 0)) { com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeEnum(2, type_); } if (((bitField0_ & 0x00000004) != 0)) { output.writeDouble(3, doubleValue_); } if (((bitField0_ & 0x00000008) != 0)) { output.writeFloat(4, floatValue_); } if (((bitField0_ & 0x00000010) != 0)) { output.writeInt64(5, longValue_); } if (((bitField0_ & 0x00000020) != 0)) { output.writeInt32(6, intValue_); } if (((bitField0_ & 0x00000040) != 0)) { output.writeBool(7, boolValue_); } if (((bitField0_ & 0x00000080) != 0)) { com.google.protobuf.GeneratedMessage.writeString(output, 8, stringValue_); } if (((bitField0_ & 0x00000100) != 0)) { output.writeBytes(9, bytesValue_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeEnumSize(2, type_); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(3, doubleValue_); } if (((bitField0_ & 0x00000008) != 0)) { size += com.google.protobuf.CodedOutputStream .computeFloatSize(4, floatValue_); } if (((bitField0_ & 0x00000010) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(5, longValue_); } if (((bitField0_ & 0x00000020) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(6, intValue_); } if (((bitField0_ & 0x00000040) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBoolSize(7, boolValue_); } if (((bitField0_ & 0x00000080) != 0)) { size += com.google.protobuf.GeneratedMessage.computeStringSize(8, stringValue_); } if (((bitField0_ & 0x00000100) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(9, bytesValue_); } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)) { return super.equals(obj); } org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) obj; if (hasName() != other.hasName()) return false; if (hasName()) { if (!getName() .equals(other.getName())) return false; } if (hasType() != other.hasType()) return false; if (hasType()) { if (type_ != other.type_) return false; } if (hasDoubleValue() != other.hasDoubleValue()) return false; if (hasDoubleValue()) { if (java.lang.Double.doubleToLongBits(getDoubleValue()) != java.lang.Double.doubleToLongBits( other.getDoubleValue())) return false; } if (hasFloatValue() != other.hasFloatValue()) return false; if (hasFloatValue()) { if (java.lang.Float.floatToIntBits(getFloatValue()) != java.lang.Float.floatToIntBits( other.getFloatValue())) return false; } if (hasLongValue() != other.hasLongValue()) return false; if (hasLongValue()) { if (getLongValue() != other.getLongValue()) return false; } if (hasIntValue() != other.hasIntValue()) return false; if (hasIntValue()) { if (getIntValue() != other.getIntValue()) return false; } if (hasBoolValue() != other.hasBoolValue()) return false; if (hasBoolValue()) { if (getBoolValue() != other.getBoolValue()) return false; } if (hasStringValue() != other.hasStringValue()) return false; if (hasStringValue()) { if (!getStringValue() .equals(other.getStringValue())) return false; } if (hasBytesValue() != other.hasBytesValue()) return false; if (hasBytesValue()) { if (!getBytesValue() .equals(other.getBytesValue())) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasName()) { hash = (37 * hash) + NAME_FIELD_NUMBER; hash = (53 * hash) + getName().hashCode(); } if (hasType()) { hash = (37 * hash) + TYPE_FIELD_NUMBER; hash = (53 * hash) + type_; } if (hasDoubleValue()) { hash = (37 * hash) + DOUBLE_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getDoubleValue())); } if (hasFloatValue()) { hash = (37 * hash) + FLOAT_VALUE_FIELD_NUMBER; hash = (53 * hash) + java.lang.Float.floatToIntBits( getFloatValue()); } if (hasLongValue()) { hash = (37 * hash) + LONG_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getLongValue()); } if (hasIntValue()) { hash = (37 * hash) + INT_VALUE_FIELD_NUMBER; hash = (53 * hash) + getIntValue(); } if (hasBoolValue()) { hash = (37 * hash) + BOOL_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( getBoolValue()); } if (hasStringValue()) { hash = (37 * hash) + STRING_VALUE_FIELD_NUMBER; hash = (53 * hash) + getStringValue().hashCode(); } if (hasBytesValue()) { hash = (37 * hash) + BYTES_VALUE_FIELD_NUMBER; hash = (53 * hash) + getBytesValue().hashCode(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraMetric) org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class); } // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.newBuilder() private Builder() { } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; name_ = ""; type_ = 0; doubleValue_ = 0D; floatValue_ = 0F; longValue_ = 0L; intValue_ = 0; boolValue_ = false; stringValue_ = ""; bytesValue_ = com.google.protobuf.ByteString.EMPTY; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric build() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric buildPartial() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(this); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.name_ = name_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.type_ = type_; to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000004) != 0)) { result.doubleValue_ = doubleValue_; to_bitField0_ |= 0x00000004; } if (((from_bitField0_ & 0x00000008) != 0)) { result.floatValue_ = floatValue_; to_bitField0_ |= 0x00000008; } if (((from_bitField0_ & 0x00000010) != 0)) { result.longValue_ = longValue_; to_bitField0_ |= 0x00000010; } if (((from_bitField0_ & 0x00000020) != 0)) { result.intValue_ = intValue_; to_bitField0_ |= 0x00000020; } if (((from_bitField0_ & 0x00000040) != 0)) { result.boolValue_ = boolValue_; to_bitField0_ |= 0x00000040; } if (((from_bitField0_ & 0x00000080) != 0)) { result.stringValue_ = stringValue_; to_bitField0_ |= 0x00000080; } if (((from_bitField0_ & 0x00000100) != 0)) { result.bytesValue_ = bytesValue_; to_bitField0_ |= 0x00000100; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) { return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other) { if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()) return this; if (other.hasName()) { name_ = other.name_; bitField0_ |= 0x00000001; onChanged(); } if (other.hasType()) { setType(other.getType()); } if (other.hasDoubleValue()) { setDoubleValue(other.getDoubleValue()); } if (other.hasFloatValue()) { setFloatValue(other.getFloatValue()); } if (other.hasLongValue()) { setLongValue(other.getLongValue()); } if (other.hasIntValue()) { setIntValue(other.getIntValue()); } if (other.hasBoolValue()) { setBoolValue(other.getBoolValue()); } if (other.hasStringValue()) { stringValue_ = other.stringValue_; bitField0_ |= 0x00000080; onChanged(); } if (other.hasBytesValue()) { setBytesValue(other.getBytesValue()); } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (!hasName()) { return false; } if (!hasType()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 10: { name_ = input.readBytes(); bitField0_ |= 0x00000001; break; } // case 10 case 16: { int tmpRaw = input.readEnum(); org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType tmpValue = org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(tmpRaw); if (tmpValue == null) { mergeUnknownVarintField(2, tmpRaw); } else { type_ = tmpRaw; bitField0_ |= 0x00000002; } break; } // case 16 case 25: { doubleValue_ = input.readDouble(); bitField0_ |= 0x00000004; break; } // case 25 case 37: { floatValue_ = input.readFloat(); bitField0_ |= 0x00000008; break; } // case 37 case 40: { longValue_ = input.readInt64(); bitField0_ |= 0x00000010; break; } // case 40 case 48: { intValue_ = input.readInt32(); bitField0_ |= 0x00000020; break; } // case 48 case 56: { boolValue_ = input.readBool(); bitField0_ |= 0x00000040; break; } // case 56 case 66: { stringValue_ = input.readBytes(); bitField0_ |= 0x00000080; break; } // case 66 case 74: { bytesValue_ = input.readBytes(); bitField0_ |= 0x00000100; break; } // case 74 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private java.lang.Object name_ = ""; /** * required string name = 1; * @return Whether the name field is set. */ public boolean hasName() { return ((bitField0_ & 0x00000001) != 0); } /** * required string name = 1; * @return The name. */ public java.lang.String getName() { java.lang.Object ref = name_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { name_ = s; } return s; } else { return (java.lang.String) ref; } } /** * required string name = 1; * @return The bytes for name. */ public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * required string name = 1; * @param value The name to set. * @return This builder for chaining. */ public Builder setName( java.lang.String value) { if (value == null) { throw new NullPointerException(); } name_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * required string name = 1; * @return This builder for chaining. */ public Builder clearName() { name_ = getDefaultInstance().getName(); bitField0_ = (bitField0_ & ~0x00000001); onChanged(); return this; } /** * required string name = 1; * @param value The bytes for name to set. * @return This builder for chaining. */ public Builder setNameBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } name_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } private int type_ = 0; /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ @java.lang.Override public boolean hasType() { return ((bitField0_ & 0x00000002) != 0); } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_); return result == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result; } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @param value The type to set. * @return This builder for chaining. */ public Builder setType(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000002; type_ = value.getNumber(); onChanged(); return this; } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return This builder for chaining. */ public Builder clearType() { bitField0_ = (bitField0_ & ~0x00000002); type_ = 0; onChanged(); return this; } private double doubleValue_ ; /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ @java.lang.Override public boolean hasDoubleValue() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double double_value = 3; * @return The doubleValue. */ @java.lang.Override public double getDoubleValue() { return doubleValue_; } /** * optional double double_value = 3; * @param value The doubleValue to set. * @return This builder for chaining. */ public Builder setDoubleValue(double value) { doubleValue_ = value; bitField0_ |= 0x00000004; onChanged(); return this; } /** * optional double double_value = 3; * @return This builder for chaining. */ public Builder clearDoubleValue() { bitField0_ = (bitField0_ & ~0x00000004); doubleValue_ = 0D; onChanged(); return this; } private float floatValue_ ; /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ @java.lang.Override public boolean hasFloatValue() { return ((bitField0_ & 0x00000008) != 0); } /** * optional float float_value = 4; * @return The floatValue. */ @java.lang.Override public float getFloatValue() { return floatValue_; } /** * optional float float_value = 4; * @param value The floatValue to set. * @return This builder for chaining. */ public Builder setFloatValue(float value) { floatValue_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** * optional float float_value = 4; * @return This builder for chaining. */ public Builder clearFloatValue() { bitField0_ = (bitField0_ & ~0x00000008); floatValue_ = 0F; onChanged(); return this; } private long longValue_ ; /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ @java.lang.Override public boolean hasLongValue() { return ((bitField0_ & 0x00000010) != 0); } /** * optional int64 long_value = 5; * @return The longValue. */ @java.lang.Override public long getLongValue() { return longValue_; } /** * optional int64 long_value = 5; * @param value The longValue to set. * @return This builder for chaining. */ public Builder setLongValue(long value) { longValue_ = value; bitField0_ |= 0x00000010; onChanged(); return this; } /** * optional int64 long_value = 5; * @return This builder for chaining. */ public Builder clearLongValue() { bitField0_ = (bitField0_ & ~0x00000010); longValue_ = 0L; onChanged(); return this; } private int intValue_ ; /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ @java.lang.Override public boolean hasIntValue() { return ((bitField0_ & 0x00000020) != 0); } /** * optional int32 int_value = 6; * @return The intValue. */ @java.lang.Override public int getIntValue() { return intValue_; } /** * optional int32 int_value = 6; * @param value The intValue to set. * @return This builder for chaining. */ public Builder setIntValue(int value) { intValue_ = value; bitField0_ |= 0x00000020; onChanged(); return this; } /** * optional int32 int_value = 6; * @return This builder for chaining. */ public Builder clearIntValue() { bitField0_ = (bitField0_ & ~0x00000020); intValue_ = 0; onChanged(); return this; } private boolean boolValue_ ; /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ @java.lang.Override public boolean hasBoolValue() { return ((bitField0_ & 0x00000040) != 0); } /** * optional bool bool_value = 7; * @return The boolValue. */ @java.lang.Override public boolean getBoolValue() { return boolValue_; } /** * optional bool bool_value = 7; * @param value The boolValue to set. * @return This builder for chaining. */ public Builder setBoolValue(boolean value) { boolValue_ = value; bitField0_ |= 0x00000040; onChanged(); return this; } /** * optional bool bool_value = 7; * @return This builder for chaining. */ public Builder clearBoolValue() { bitField0_ = (bitField0_ & ~0x00000040); boolValue_ = false; onChanged(); return this; } private java.lang.Object stringValue_ = ""; /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ public boolean hasStringValue() { return ((bitField0_ & 0x00000080) != 0); } /** * optional string string_value = 8; * @return The stringValue. */ public java.lang.String getStringValue() { java.lang.Object ref = stringValue_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { stringValue_ = s; } return s; } else { return (java.lang.String) ref; } } /** * optional string string_value = 8; * @return The bytes for stringValue. */ public com.google.protobuf.ByteString getStringValueBytes() { java.lang.Object ref = stringValue_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); stringValue_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * optional string string_value = 8; * @param value The stringValue to set. * @return This builder for chaining. */ public Builder setStringValue( java.lang.String value) { if (value == null) { throw new NullPointerException(); } stringValue_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } /** * optional string string_value = 8; * @return This builder for chaining. */ public Builder clearStringValue() { stringValue_ = getDefaultInstance().getStringValue(); bitField0_ = (bitField0_ & ~0x00000080); onChanged(); return this; } /** * optional string string_value = 8; * @param value The bytes for stringValue to set. * @return This builder for chaining. */ public Builder setStringValueBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } stringValue_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ @java.lang.Override public boolean hasBytesValue() { return ((bitField0_ & 0x00000100) != 0); } /** * optional bytes bytes_value = 9; * @return The bytesValue. */ @java.lang.Override public com.google.protobuf.ByteString getBytesValue() { return bytesValue_; } /** * optional bytes bytes_value = 9; * @param value The bytesValue to set. * @return This builder for chaining. */ public Builder setBytesValue(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } bytesValue_ = value; bitField0_ |= 0x00000100; onChanged(); return this; } /** * optional bytes bytes_value = 9; * @return This builder for chaining. */ public Builder clearBytesValue() { bitField0_ = (bitField0_ & ~0x00000100); bytesValue_ = getDefaultInstance().getBytesValue(); onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraMetric) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraMetric) private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraMetric parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } public interface KuraPositionOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraPosition) com.google.protobuf.MessageOrBuilder { /** * required double latitude = 1; * @return Whether the latitude field is set. */ boolean hasLatitude(); /** * required double latitude = 1; * @return The latitude. */ double getLatitude(); /** * required double longitude = 2; * @return Whether the longitude field is set. */ boolean hasLongitude(); /** * required double longitude = 2; * @return The longitude. */ double getLongitude(); /** * optional double altitude = 3; * @return Whether the altitude field is set. */ boolean hasAltitude(); /** * optional double altitude = 3; * @return The altitude. */ double getAltitude(); /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return Whether the precision field is set. */ boolean hasPrecision(); /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return The precision. */ double getPrecision(); /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return Whether the heading field is set. */ boolean hasHeading(); /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return The heading. */ double getHeading(); /** *
       * meters per second
       * 
* * optional double speed = 6; * @return Whether the speed field is set. */ boolean hasSpeed(); /** *
       * meters per second
       * 
* * optional double speed = 6; * @return The speed. */ double getSpeed(); /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ boolean hasTimestamp(); /** * optional int64 timestamp = 7; * @return The timestamp. */ long getTimestamp(); /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ boolean hasSatellites(); /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return The satellites. */ int getSatellites(); /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return Whether the status field is set. */ boolean hasStatus(); /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return The status. */ int getStatus(); } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition} */ public static final class KuraPosition extends com.google.protobuf.GeneratedMessage implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraPosition) KuraPositionOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPosition.class.getName()); } // Use KuraPosition.newBuilder() to construct. private KuraPosition(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } private KuraPosition() { } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class); } private int bitField0_; public static final int LATITUDE_FIELD_NUMBER = 1; private double latitude_ = 0D; /** * required double latitude = 1; * @return Whether the latitude field is set. */ @java.lang.Override public boolean hasLatitude() { return ((bitField0_ & 0x00000001) != 0); } /** * required double latitude = 1; * @return The latitude. */ @java.lang.Override public double getLatitude() { return latitude_; } public static final int LONGITUDE_FIELD_NUMBER = 2; private double longitude_ = 0D; /** * required double longitude = 2; * @return Whether the longitude field is set. */ @java.lang.Override public boolean hasLongitude() { return ((bitField0_ & 0x00000002) != 0); } /** * required double longitude = 2; * @return The longitude. */ @java.lang.Override public double getLongitude() { return longitude_; } public static final int ALTITUDE_FIELD_NUMBER = 3; private double altitude_ = 0D; /** * optional double altitude = 3; * @return Whether the altitude field is set. */ @java.lang.Override public boolean hasAltitude() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double altitude = 3; * @return The altitude. */ @java.lang.Override public double getAltitude() { return altitude_; } public static final int PRECISION_FIELD_NUMBER = 4; private double precision_ = 0D; /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return Whether the precision field is set. */ @java.lang.Override public boolean hasPrecision() { return ((bitField0_ & 0x00000008) != 0); } /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return The precision. */ @java.lang.Override public double getPrecision() { return precision_; } public static final int HEADING_FIELD_NUMBER = 5; private double heading_ = 0D; /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return Whether the heading field is set. */ @java.lang.Override public boolean hasHeading() { return ((bitField0_ & 0x00000010) != 0); } /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return The heading. */ @java.lang.Override public double getHeading() { return heading_; } public static final int SPEED_FIELD_NUMBER = 6; private double speed_ = 0D; /** *
       * meters per second
       * 
* * optional double speed = 6; * @return Whether the speed field is set. */ @java.lang.Override public boolean hasSpeed() { return ((bitField0_ & 0x00000020) != 0); } /** *
       * meters per second
       * 
* * optional double speed = 6; * @return The speed. */ @java.lang.Override public double getSpeed() { return speed_; } public static final int TIMESTAMP_FIELD_NUMBER = 7; private long timestamp_ = 0L; /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000040) != 0); } /** * optional int64 timestamp = 7; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } public static final int SATELLITES_FIELD_NUMBER = 8; private int satellites_ = 0; /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ @java.lang.Override public boolean hasSatellites() { return ((bitField0_ & 0x00000080) != 0); } /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return The satellites. */ @java.lang.Override public int getSatellites() { return satellites_; } public static final int STATUS_FIELD_NUMBER = 9; private int status_ = 0; /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return Whether the status field is set. */ @java.lang.Override public boolean hasStatus() { return ((bitField0_ & 0x00000100) != 0); } /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return The status. */ @java.lang.Override public int getStatus() { return status_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (!hasLatitude()) { memoizedIsInitialized = 0; return false; } if (!hasLongitude()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (((bitField0_ & 0x00000001) != 0)) { output.writeDouble(1, latitude_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeDouble(2, longitude_); } if (((bitField0_ & 0x00000004) != 0)) { output.writeDouble(3, altitude_); } if (((bitField0_ & 0x00000008) != 0)) { output.writeDouble(4, precision_); } if (((bitField0_ & 0x00000010) != 0)) { output.writeDouble(5, heading_); } if (((bitField0_ & 0x00000020) != 0)) { output.writeDouble(6, speed_); } if (((bitField0_ & 0x00000040) != 0)) { output.writeInt64(7, timestamp_); } if (((bitField0_ & 0x00000080) != 0)) { output.writeInt32(8, satellites_); } if (((bitField0_ & 0x00000100) != 0)) { output.writeInt32(9, status_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(1, latitude_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(2, longitude_); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(3, altitude_); } if (((bitField0_ & 0x00000008) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(4, precision_); } if (((bitField0_ & 0x00000010) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(5, heading_); } if (((bitField0_ & 0x00000020) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(6, speed_); } if (((bitField0_ & 0x00000040) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(7, timestamp_); } if (((bitField0_ & 0x00000080) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(8, satellites_); } if (((bitField0_ & 0x00000100) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(9, status_); } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)) { return super.equals(obj); } org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) obj; if (hasLatitude() != other.hasLatitude()) return false; if (hasLatitude()) { if (java.lang.Double.doubleToLongBits(getLatitude()) != java.lang.Double.doubleToLongBits( other.getLatitude())) return false; } if (hasLongitude() != other.hasLongitude()) return false; if (hasLongitude()) { if (java.lang.Double.doubleToLongBits(getLongitude()) != java.lang.Double.doubleToLongBits( other.getLongitude())) return false; } if (hasAltitude() != other.hasAltitude()) return false; if (hasAltitude()) { if (java.lang.Double.doubleToLongBits(getAltitude()) != java.lang.Double.doubleToLongBits( other.getAltitude())) return false; } if (hasPrecision() != other.hasPrecision()) return false; if (hasPrecision()) { if (java.lang.Double.doubleToLongBits(getPrecision()) != java.lang.Double.doubleToLongBits( other.getPrecision())) return false; } if (hasHeading() != other.hasHeading()) return false; if (hasHeading()) { if (java.lang.Double.doubleToLongBits(getHeading()) != java.lang.Double.doubleToLongBits( other.getHeading())) return false; } if (hasSpeed() != other.hasSpeed()) return false; if (hasSpeed()) { if (java.lang.Double.doubleToLongBits(getSpeed()) != java.lang.Double.doubleToLongBits( other.getSpeed())) return false; } if (hasTimestamp() != other.hasTimestamp()) return false; if (hasTimestamp()) { if (getTimestamp() != other.getTimestamp()) return false; } if (hasSatellites() != other.hasSatellites()) return false; if (hasSatellites()) { if (getSatellites() != other.getSatellites()) return false; } if (hasStatus() != other.hasStatus()) return false; if (hasStatus()) { if (getStatus() != other.getStatus()) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasLatitude()) { hash = (37 * hash) + LATITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getLatitude())); } if (hasLongitude()) { hash = (37 * hash) + LONGITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getLongitude())); } if (hasAltitude()) { hash = (37 * hash) + ALTITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getAltitude())); } if (hasPrecision()) { hash = (37 * hash) + PRECISION_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getPrecision())); } if (hasHeading()) { hash = (37 * hash) + HEADING_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getHeading())); } if (hasSpeed()) { hash = (37 * hash) + SPEED_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getSpeed())); } if (hasTimestamp()) { hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getTimestamp()); } if (hasSatellites()) { hash = (37 * hash) + SATELLITES_FIELD_NUMBER; hash = (53 * hash) + getSatellites(); } if (hasStatus()) { hash = (37 * hash) + STATUS_FIELD_NUMBER; hash = (53 * hash) + getStatus(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraPosition) org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class); } // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.newBuilder() private Builder() { } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; latitude_ = 0D; longitude_ = 0D; altitude_ = 0D; precision_ = 0D; heading_ = 0D; speed_ = 0D; timestamp_ = 0L; satellites_ = 0; status_ = 0; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition build() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition buildPartial() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(this); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.latitude_ = latitude_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.longitude_ = longitude_; to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000004) != 0)) { result.altitude_ = altitude_; to_bitField0_ |= 0x00000004; } if (((from_bitField0_ & 0x00000008) != 0)) { result.precision_ = precision_; to_bitField0_ |= 0x00000008; } if (((from_bitField0_ & 0x00000010) != 0)) { result.heading_ = heading_; to_bitField0_ |= 0x00000010; } if (((from_bitField0_ & 0x00000020) != 0)) { result.speed_ = speed_; to_bitField0_ |= 0x00000020; } if (((from_bitField0_ & 0x00000040) != 0)) { result.timestamp_ = timestamp_; to_bitField0_ |= 0x00000040; } if (((from_bitField0_ & 0x00000080) != 0)) { result.satellites_ = satellites_; to_bitField0_ |= 0x00000080; } if (((from_bitField0_ & 0x00000100) != 0)) { result.status_ = status_; to_bitField0_ |= 0x00000100; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) { return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other) { if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) return this; if (other.hasLatitude()) { setLatitude(other.getLatitude()); } if (other.hasLongitude()) { setLongitude(other.getLongitude()); } if (other.hasAltitude()) { setAltitude(other.getAltitude()); } if (other.hasPrecision()) { setPrecision(other.getPrecision()); } if (other.hasHeading()) { setHeading(other.getHeading()); } if (other.hasSpeed()) { setSpeed(other.getSpeed()); } if (other.hasTimestamp()) { setTimestamp(other.getTimestamp()); } if (other.hasSatellites()) { setSatellites(other.getSatellites()); } if (other.hasStatus()) { setStatus(other.getStatus()); } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (!hasLatitude()) { return false; } if (!hasLongitude()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 9: { latitude_ = input.readDouble(); bitField0_ |= 0x00000001; break; } // case 9 case 17: { longitude_ = input.readDouble(); bitField0_ |= 0x00000002; break; } // case 17 case 25: { altitude_ = input.readDouble(); bitField0_ |= 0x00000004; break; } // case 25 case 33: { precision_ = input.readDouble(); bitField0_ |= 0x00000008; break; } // case 33 case 41: { heading_ = input.readDouble(); bitField0_ |= 0x00000010; break; } // case 41 case 49: { speed_ = input.readDouble(); bitField0_ |= 0x00000020; break; } // case 49 case 56: { timestamp_ = input.readInt64(); bitField0_ |= 0x00000040; break; } // case 56 case 64: { satellites_ = input.readInt32(); bitField0_ |= 0x00000080; break; } // case 64 case 72: { status_ = input.readInt32(); bitField0_ |= 0x00000100; break; } // case 72 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private double latitude_ ; /** * required double latitude = 1; * @return Whether the latitude field is set. */ @java.lang.Override public boolean hasLatitude() { return ((bitField0_ & 0x00000001) != 0); } /** * required double latitude = 1; * @return The latitude. */ @java.lang.Override public double getLatitude() { return latitude_; } /** * required double latitude = 1; * @param value The latitude to set. * @return This builder for chaining. */ public Builder setLatitude(double value) { latitude_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * required double latitude = 1; * @return This builder for chaining. */ public Builder clearLatitude() { bitField0_ = (bitField0_ & ~0x00000001); latitude_ = 0D; onChanged(); return this; } private double longitude_ ; /** * required double longitude = 2; * @return Whether the longitude field is set. */ @java.lang.Override public boolean hasLongitude() { return ((bitField0_ & 0x00000002) != 0); } /** * required double longitude = 2; * @return The longitude. */ @java.lang.Override public double getLongitude() { return longitude_; } /** * required double longitude = 2; * @param value The longitude to set. * @return This builder for chaining. */ public Builder setLongitude(double value) { longitude_ = value; bitField0_ |= 0x00000002; onChanged(); return this; } /** * required double longitude = 2; * @return This builder for chaining. */ public Builder clearLongitude() { bitField0_ = (bitField0_ & ~0x00000002); longitude_ = 0D; onChanged(); return this; } private double altitude_ ; /** * optional double altitude = 3; * @return Whether the altitude field is set. */ @java.lang.Override public boolean hasAltitude() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double altitude = 3; * @return The altitude. */ @java.lang.Override public double getAltitude() { return altitude_; } /** * optional double altitude = 3; * @param value The altitude to set. * @return This builder for chaining. */ public Builder setAltitude(double value) { altitude_ = value; bitField0_ |= 0x00000004; onChanged(); return this; } /** * optional double altitude = 3; * @return This builder for chaining. */ public Builder clearAltitude() { bitField0_ = (bitField0_ & ~0x00000004); altitude_ = 0D; onChanged(); return this; } private double precision_ ; /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return Whether the precision field is set. */ @java.lang.Override public boolean hasPrecision() { return ((bitField0_ & 0x00000008) != 0); } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return The precision. */ @java.lang.Override public double getPrecision() { return precision_; } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @param value The precision to set. * @return This builder for chaining. */ public Builder setPrecision(double value) { precision_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return This builder for chaining. */ public Builder clearPrecision() { bitField0_ = (bitField0_ & ~0x00000008); precision_ = 0D; onChanged(); return this; } private double heading_ ; /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return Whether the heading field is set. */ @java.lang.Override public boolean hasHeading() { return ((bitField0_ & 0x00000010) != 0); } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return The heading. */ @java.lang.Override public double getHeading() { return heading_; } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @param value The heading to set. * @return This builder for chaining. */ public Builder setHeading(double value) { heading_ = value; bitField0_ |= 0x00000010; onChanged(); return this; } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return This builder for chaining. */ public Builder clearHeading() { bitField0_ = (bitField0_ & ~0x00000010); heading_ = 0D; onChanged(); return this; } private double speed_ ; /** *
         * meters per second
         * 
* * optional double speed = 6; * @return Whether the speed field is set. */ @java.lang.Override public boolean hasSpeed() { return ((bitField0_ & 0x00000020) != 0); } /** *
         * meters per second
         * 
* * optional double speed = 6; * @return The speed. */ @java.lang.Override public double getSpeed() { return speed_; } /** *
         * meters per second
         * 
* * optional double speed = 6; * @param value The speed to set. * @return This builder for chaining. */ public Builder setSpeed(double value) { speed_ = value; bitField0_ |= 0x00000020; onChanged(); return this; } /** *
         * meters per second
         * 
* * optional double speed = 6; * @return This builder for chaining. */ public Builder clearSpeed() { bitField0_ = (bitField0_ & ~0x00000020); speed_ = 0D; onChanged(); return this; } private long timestamp_ ; /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000040) != 0); } /** * optional int64 timestamp = 7; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } /** * optional int64 timestamp = 7; * @param value The timestamp to set. * @return This builder for chaining. */ public Builder setTimestamp(long value) { timestamp_ = value; bitField0_ |= 0x00000040; onChanged(); return this; } /** * optional int64 timestamp = 7; * @return This builder for chaining. */ public Builder clearTimestamp() { bitField0_ = (bitField0_ & ~0x00000040); timestamp_ = 0L; onChanged(); return this; } private int satellites_ ; /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ @java.lang.Override public boolean hasSatellites() { return ((bitField0_ & 0x00000080) != 0); } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return The satellites. */ @java.lang.Override public int getSatellites() { return satellites_; } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @param value The satellites to set. * @return This builder for chaining. */ public Builder setSatellites(int value) { satellites_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return This builder for chaining. */ public Builder clearSatellites() { bitField0_ = (bitField0_ & ~0x00000080); satellites_ = 0; onChanged(); return this; } private int status_ ; /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return Whether the status field is set. */ @java.lang.Override public boolean hasStatus() { return ((bitField0_ & 0x00000100) != 0); } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return The status. */ @java.lang.Override public int getStatus() { return status_; } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @param value The status to set. * @return This builder for chaining. */ public Builder setStatus(int value) { status_ = value; bitField0_ |= 0x00000100; onChanged(); return this; } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return This builder for chaining. */ public Builder clearStatus() { bitField0_ = (bitField0_ & ~0x00000100); status_ = 0; onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraPosition) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraPosition) private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraPosition parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private int bitField0_; public static final int TIMESTAMP_FIELD_NUMBER = 1; private long timestamp_ = 0L; /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000001) != 0); } /** * optional int64 timestamp = 1; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } public static final int POSITION_FIELD_NUMBER = 2; private org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_; /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ @java.lang.Override public boolean hasPosition() { return ((bitField0_ & 0x00000002) != 0); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() { return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() { return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } public static final int METRIC_FIELD_NUMBER = 5000; @SuppressWarnings("serial") private java.util.List metric_; /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public java.util.List getMetricList() { return metric_; } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public java.util.List getMetricOrBuilderList() { return metric_; } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public int getMetricCount() { return metric_.size(); } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) { return metric_.get(index); } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index) { return metric_.get(index); } public static final int BODY_FIELD_NUMBER = 5001; private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes body = 5001; * @return Whether the body field is set. */ @java.lang.Override public boolean hasBody() { return ((bitField0_ & 0x00000004) != 0); } /** * optional bytes body = 5001; * @return The body. */ @java.lang.Override public com.google.protobuf.ByteString getBody() { return body_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (hasPosition()) { if (!getPosition().isInitialized()) { memoizedIsInitialized = 0; return false; } } for (int i = 0; i < getMetricCount(); i++) { if (!getMetric(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } if (!extensionsAreInitialized()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { com.google.protobuf.GeneratedMessage .ExtendableMessage.ExtensionSerializer extensionWriter = newExtensionSerializer(); if (((bitField0_ & 0x00000001) != 0)) { output.writeInt64(1, timestamp_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeMessage(2, getPosition()); } extensionWriter.writeUntil(5000, output); for (int i = 0; i < metric_.size(); i++) { output.writeMessage(5000, metric_.get(i)); } if (((bitField0_ & 0x00000004) != 0)) { output.writeBytes(5001, body_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(1, timestamp_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(2, getPosition()); } for (int i = 0; i < metric_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(5000, metric_.get(i)); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(5001, body_); } size += extensionsSerializedSize(); size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload)) { return super.equals(obj); } org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload other = (org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload) obj; if (hasTimestamp() != other.hasTimestamp()) return false; if (hasTimestamp()) { if (getTimestamp() != other.getTimestamp()) return false; } if (hasPosition() != other.hasPosition()) return false; if (hasPosition()) { if (!getPosition() .equals(other.getPosition())) return false; } if (!getMetricList() .equals(other.getMetricList())) return false; if (hasBody() != other.hasBody()) return false; if (hasBody()) { if (!getBody() .equals(other.getBody())) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; if (!getExtensionFields().equals(other.getExtensionFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasTimestamp()) { hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getTimestamp()); } if (hasPosition()) { hash = (37 * hash) + POSITION_FIELD_NUMBER; hash = (53 * hash) + getPosition().hashCode(); } if (getMetricCount() > 0) { hash = (37 * hash) + METRIC_FIELD_NUMBER; hash = (53 * hash) + getMetricList().hashCode(); } if (hasBody()) { hash = (37 * hash) + BODY_FIELD_NUMBER; hash = (53 * hash) + getBody().hashCode(); } hash = hashFields(hash, getExtensionFields()); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.ExtendableBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload, Builder> implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload) org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayloadOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class); } // Construct using org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage .alwaysUseFieldBuilders) { getPositionFieldBuilder(); getMetricFieldBuilder(); } } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; timestamp_ = 0L; position_ = null; if (positionBuilder_ != null) { positionBuilder_.dispose(); positionBuilder_ = null; } if (metricBuilder_ == null) { metric_ = java.util.Collections.emptyList(); } else { metric_ = null; metricBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000004); body_ = com.google.protobuf.ByteString.EMPTY; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() { return org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload build() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload buildPartial() { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload(this); buildPartialRepeatedFields(result); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartialRepeatedFields(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result) { if (metricBuilder_ == null) { if (((bitField0_ & 0x00000004) != 0)) { metric_ = java.util.Collections.unmodifiableList(metric_); bitField0_ = (bitField0_ & ~0x00000004); } result.metric_ = metric_; } else { result.metric_ = metricBuilder_.build(); } } private void buildPartial0(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.timestamp_ = timestamp_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.position_ = positionBuilder_ == null ? position_ : positionBuilder_.build(); to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000008) != 0)) { result.body_ = body_; to_bitField0_ |= 0x00000004; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload) { return mergeFrom((org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload other) { if (other == org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance()) return this; if (other.hasTimestamp()) { setTimestamp(other.getTimestamp()); } if (other.hasPosition()) { mergePosition(other.getPosition()); } if (metricBuilder_ == null) { if (!other.metric_.isEmpty()) { if (metric_.isEmpty()) { metric_ = other.metric_; bitField0_ = (bitField0_ & ~0x00000004); } else { ensureMetricIsMutable(); metric_.addAll(other.metric_); } onChanged(); } } else { if (!other.metric_.isEmpty()) { if (metricBuilder_.isEmpty()) { metricBuilder_.dispose(); metricBuilder_ = null; metric_ = other.metric_; bitField0_ = (bitField0_ & ~0x00000004); metricBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getMetricFieldBuilder() : null; } else { metricBuilder_.addAllMessages(other.metric_); } } } if (other.hasBody()) { setBody(other.getBody()); } this.mergeExtensionFields(other); this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (hasPosition()) { if (!getPosition().isInitialized()) { return false; } } for (int i = 0; i < getMetricCount(); i++) { if (!getMetric(i).isInitialized()) { return false; } } if (!extensionsAreInitialized()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 8: { timestamp_ = input.readInt64(); bitField0_ |= 0x00000001; break; } // case 8 case 18: { input.readMessage( getPositionFieldBuilder().getBuilder(), extensionRegistry); bitField0_ |= 0x00000002; break; } // case 18 case 40002: { org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric m = input.readMessage( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.parser(), extensionRegistry); if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(m); } else { metricBuilder_.addMessage(m); } break; } // case 40002 case 40010: { body_ = input.readBytes(); bitField0_ |= 0x00000008; break; } // case 40010 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private long timestamp_ ; /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000001) != 0); } /** * optional int64 timestamp = 1; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } /** * optional int64 timestamp = 1; * @param value The timestamp to set. * @return This builder for chaining. */ public Builder setTimestamp(long value) { timestamp_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * optional int64 timestamp = 1; * @return This builder for chaining. */ public Builder clearTimestamp() { bitField0_ = (bitField0_ & ~0x00000001); timestamp_ = 0L; onChanged(); return this; } private org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_; private com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> positionBuilder_; /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ public boolean hasPosition() { return ((bitField0_ & 0x00000002) != 0); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() { if (positionBuilder_ == null) { return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } else { return positionBuilder_.getMessage(); } } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder setPosition(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) { if (positionBuilder_ == null) { if (value == null) { throw new NullPointerException(); } position_ = value; } else { positionBuilder_.setMessage(value); } bitField0_ |= 0x00000002; onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder setPosition( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder builderForValue) { if (positionBuilder_ == null) { position_ = builderForValue.build(); } else { positionBuilder_.setMessage(builderForValue.build()); } bitField0_ |= 0x00000002; onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder mergePosition(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) { if (positionBuilder_ == null) { if (((bitField0_ & 0x00000002) != 0) && position_ != null && position_ != org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) { getPositionBuilder().mergeFrom(value); } else { position_ = value; } } else { positionBuilder_.mergeFrom(value); } if (position_ != null) { bitField0_ |= 0x00000002; onChanged(); } return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder clearPosition() { bitField0_ = (bitField0_ & ~0x00000002); position_ = null; if (positionBuilder_ != null) { positionBuilder_.dispose(); positionBuilder_ = null; } onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder getPositionBuilder() { bitField0_ |= 0x00000002; onChanged(); return getPositionFieldBuilder().getBuilder(); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() { if (positionBuilder_ != null) { return positionBuilder_.getMessageOrBuilder(); } else { return position_ == null ? org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ private com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> getPositionFieldBuilder() { if (positionBuilder_ == null) { positionBuilder_ = new com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder>( getPosition(), getParentForChildren(), isClean()); position_ = null; } return positionBuilder_; } private java.util.List metric_ = java.util.Collections.emptyList(); private void ensureMetricIsMutable() { if (!((bitField0_ & 0x00000004) != 0)) { metric_ = new java.util.ArrayList(metric_); bitField0_ |= 0x00000004; } } private com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> metricBuilder_; /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricList() { if (metricBuilder_ == null) { return java.util.Collections.unmodifiableList(metric_); } else { return metricBuilder_.getMessageList(); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public int getMetricCount() { if (metricBuilder_ == null) { return metric_.size(); } else { return metricBuilder_.getCount(); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) { if (metricBuilder_ == null) { return metric_.get(index); } else { return metricBuilder_.getMessage(index); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder setMetric( int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.set(index, value); onChanged(); } else { metricBuilder_.setMessage(index, value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder setMetric( int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.set(index, builderForValue.build()); onChanged(); } else { metricBuilder_.setMessage(index, builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric(org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.add(value); onChanged(); } else { metricBuilder_.addMessage(value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.add(index, value); onChanged(); } else { metricBuilder_.addMessage(index, value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(builderForValue.build()); onChanged(); } else { metricBuilder_.addMessage(builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( int index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(index, builderForValue.build()); onChanged(); } else { metricBuilder_.addMessage(index, builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addAllMetric( java.lang.Iterable values) { if (metricBuilder_ == null) { ensureMetricIsMutable(); com.google.protobuf.AbstractMessageLite.Builder.addAll( values, metric_); onChanged(); } else { metricBuilder_.addAllMessages(values); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder clearMetric() { if (metricBuilder_ == null) { metric_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000004); onChanged(); } else { metricBuilder_.clear(); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder removeMetric(int index) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.remove(index); onChanged(); } else { metricBuilder_.remove(index); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder getMetricBuilder( int index) { return getMetricFieldBuilder().getBuilder(index); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index) { if (metricBuilder_ == null) { return metric_.get(index); } else { return metricBuilder_.getMessageOrBuilder(index); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricOrBuilderList() { if (metricBuilder_ != null) { return metricBuilder_.getMessageOrBuilderList(); } else { return java.util.Collections.unmodifiableList(metric_); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder() { return getMetricFieldBuilder().addBuilder( org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder( int index) { return getMetricFieldBuilder().addBuilder( index, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricBuilderList() { return getMetricFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> getMetricFieldBuilder() { if (metricBuilder_ == null) { metricBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder>( metric_, ((bitField0_ & 0x00000004) != 0), getParentForChildren(), isClean()); metric_ = null; } return metricBuilder_; } private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes body = 5001; * @return Whether the body field is set. */ @java.lang.Override public boolean hasBody() { return ((bitField0_ & 0x00000008) != 0); } /** * optional bytes body = 5001; * @return The body. */ @java.lang.Override public com.google.protobuf.ByteString getBody() { return body_; } /** * optional bytes body = 5001; * @param value The body to set. * @return This builder for chaining. */ public Builder setBody(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } body_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** * optional bytes body = 5001; * @return This builder for chaining. */ public Builder clearBody() { bitField0_ = (bitField0_ & ~0x00000008); body_ = getDefaultInstance().getBody(); onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload) private static final org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload(); } public static org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraPayload parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_fieldAccessorTable; private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable; private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { java.lang.String[] descriptorData = { "\n\021kurapayload.proto\022\rkuradatatypes\"\243\005\n\013K" + "uraPayload\022\021\n\ttimestamp\030\001 \001(\003\0229\n\010positio" + "n\030\002 \001(\0132\'.kuradatatypes.KuraPayload.Kura" + "Position\0226\n\006metric\030\210\' \003(\0132%.kuradatatype" + "s.KuraPayload.KuraMetric\022\r\n\004body\030\211\' \001(\014\032" + "\305\002\n\nKuraMetric\022\014\n\004name\030\001 \002(\t\022=\n\004type\030\002 \002" + "(\0162/.kuradatatypes.KuraPayload.KuraMetri" + "c.ValueType\022\024\n\014double_value\030\003 \001(\001\022\023\n\013flo" + "at_value\030\004 \001(\002\022\022\n\nlong_value\030\005 \001(\003\022\021\n\tin" + "t_value\030\006 \001(\005\022\022\n\nbool_value\030\007 \001(\010\022\024\n\014str" + "ing_value\030\010 \001(\t\022\023\n\013bytes_value\030\t \001(\014\"Y\n\t" + "ValueType\022\n\n\006DOUBLE\020\000\022\t\n\005FLOAT\020\001\022\t\n\005INT6" + "4\020\002\022\t\n\005INT32\020\003\022\010\n\004BOOL\020\004\022\n\n\006STRING\020\005\022\t\n\005" + "BYTES\020\006\032\257\001\n\014KuraPosition\022\020\n\010latitude\030\001 \002" + "(\001\022\021\n\tlongitude\030\002 \002(\001\022\020\n\010altitude\030\003 \001(\001\022" + "\021\n\tprecision\030\004 \001(\001\022\017\n\007heading\030\005 \001(\001\022\r\n\005s" + "peed\030\006 \001(\001\022\021\n\ttimestamp\030\007 \001(\003\022\022\n\nsatelli" + "tes\030\010 \001(\005\022\016\n\006status\030\t \001(\005*\005\010\003\020\210\'B^\nJorg." + "eclipse.kura.internal.cloudconnection.ec" + "lipseiot.mqtt.message.protobufB\020KuraPayl" + "oadProto" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] { }); internal_static_kuradatatypes_KuraPayload_descriptor = getDescriptor().getMessageTypes().get(0); internal_static_kuradatatypes_KuraPayload_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_descriptor, new java.lang.String[] { "Timestamp", "Position", "Metric", "Body", }); internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor = internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(0); internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor, new java.lang.String[] { "Name", "Type", "DoubleValue", "FloatValue", "LongValue", "IntValue", "BoolValue", "StringValue", "BytesValue", }); internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor = internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(1); internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor, new java.lang.String[] { "Latitude", "Longitude", "Altitude", "Precision", "Heading", "Speed", "Timestamp", "Satellites", "Status", }); descriptor.resolveAllFeaturesImmutable(); } // @@protoc_insertion_point(outer_class_scope) } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.eclipseiot.mqtt.provider/src/main/protobuf/kurapayload.proto ================================================ // // To compile: // protoc --proto_path=src/main/protobuf --java_out=src/main/java src/main/protobuf/kurapayload.proto // syntax = "proto2"; package kuradatatypes; option java_package = "org.eclipse.kura.internal.cloudconnection.eclipseiot.mqtt.message.protobuf"; option java_outer_classname = "KuraPayloadProto"; message KuraPayload { message KuraMetric { enum ValueType { DOUBLE = 0; FLOAT = 1; INT64 = 2; INT32 = 3; BOOL = 4; STRING = 5; BYTES = 6; } required string name = 1; required ValueType type = 2; optional double double_value = 3; optional float float_value = 4; optional int64 long_value = 5; optional int32 int_value = 6; optional bool bool_value = 7; optional string string_value = 8; optional bytes bytes_value = 9; } message KuraPosition { required double latitude = 1; required double longitude = 2; optional double altitude = 3; optional double precision = 4; // dilution of precision of the current satellite fix. optional double heading = 5; // heading in degrees optional double speed = 6; // meters per second optional int64 timestamp = 7; optional int32 satellites = 8; // number satellites locked by the GPS device optional int32 status = 9; // status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid. } optional int64 timestamp = 1; optional KuraPosition position = 2; extensions 3 to 4999; repeated KuraMetric metric = 5000; // can be zero, so optional optional bytes body = 5001; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/.gitignore ================================================ /target /bin /lib ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.cloudconnection.kapua.mqtt.provider Bundle-SymbolicName: org.eclipse.kura.cloudconnection.kapua.mqtt.provider;singleton:=true Bundle-Version: 1.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: ., lib/protobuf-java.jar Bundle-ActivationPolicy: lazy Import-Package: com.eclipsesource.json;version="0.9.5", org.apache.commons.io;version="2.4.0", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.audit;version="[1.0,2.0)", org.eclipse.kura.certificate;version="[2.0,3.0)", org.eclipse.kura.cloud;version="[1.1,1.2)", org.eclipse.kura.cloud.factory;version="[1.1,1.2)", org.eclipse.kura.cloudconnection;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.factory;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.listener;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.request;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber.listener;version="[1.0,2.0)", org.eclipse.kura.command;version="[1.2,1.3)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.configuration.metatype;version="[1.1,2.0)", org.eclipse.kura.core.data;version="[1.3,2.0)", org.eclipse.kura.core.data.util;version="[1.0,2.0)", org.eclipse.kura.core.util;version="[2.0,3.0)", org.eclipse.kura.crypto;version="[1.0,2.0)", org.eclipse.kura.data;version="[1.0,2.0)", org.eclipse.kura.data.listener;version="[1.0,1.1)", org.eclipse.kura.executor;version="[1.0,2.0)", org.eclipse.kura.marshalling;version="[1.0,2.0)", org.eclipse.kura.message;version="[1.5,2.0)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.net.modem;version="[2.0,3.0)", org.eclipse.kura.net.status;version="[1.1,2.0)", org.eclipse.kura.net.status.modem;version="[1.0,2.0)", org.eclipse.kura.position;version="[1.0,2.0)", org.eclipse.kura.security.tamper.detection;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.5,2.0)", org.eclipse.kura.util.zip;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.0", org.osgi.util.measurement;version="[1.0,2.0)", org.osgi.util.position;version="[1.0,2.0)", org.osgi.util.tracker;version="1.5.1", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloud.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudCall.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/cloudSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.CloudService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.publisher.CloudPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloud.subscriber.CloudSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/,\ lib/protobuf-java.jar src.includes = about.html,\ about_files/ source.. = src/main/java/ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.cloudconnection.kapua.mqtt.provider 1.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.cloudconnection.kapua.mqtt.provider.test/target/site/jacoco-aggregate/jacoco.xml com.google.protobuf protobuf-java maven-dependency-plugin 3.8.1 copy-dependencies generate-sources copy-dependencies ${project.basedir}/lib protobuf-java true org.apache.maven.plugins maven-checkstyle-plugin true maven-clean-plugin 3.1.0 lib ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/cloud/app/RequestIdGenerator.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloud.app; import java.util.Random; public class RequestIdGenerator { private static RequestIdGenerator s_instance = new RequestIdGenerator(); private final Random m_random; private RequestIdGenerator() { super(); this.m_random = new Random(); } public static RequestIdGenerator getInstance() { return s_instance; } public String next() { long timestamp = System.currentTimeMillis(); long random; synchronized (this.m_random) { random = this.m_random.nextLong(); } return timestamp + "-" + random; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudClientImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.cloud.CloudClientListener; import org.eclipse.kura.data.DataService; import org.eclipse.kura.message.KuraPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of the CloudClient interface. */ public class CloudClientImpl implements CloudClient, CloudClientListener { @SuppressWarnings("unused") private static final Logger logger = LoggerFactory.getLogger(CloudClientImpl.class); private final String applicationId; private final DataService dataService; private final CloudServiceImpl cloudServiceImpl; private final List listeners; protected CloudClientImpl(String applicationId, DataService dataService, CloudServiceImpl cloudServiceImpl) { this.applicationId = applicationId; this.dataService = dataService; this.cloudServiceImpl = cloudServiceImpl; this.listeners = new CopyOnWriteArrayList<>(); } /** * Returns the applicationId of this CloudApplicationClient * * @return applicationId */ @Override public String getApplicationId() { return this.applicationId; } /** * Releases this CloudClient handle. This instance should no longer be used. * Note: CloudClient does not unsubscribes all subscriptions incurred by this client, * this responsibility is left to the application developer */ @Override public void release() { // remove this from being a callback handler this.cloudServiceImpl.removeCloudClient(this); } // -------------------------------------------------------------------- // // CloudCallbackHandler API // // -------------------------------------------------------------------- @Override public void addCloudClientListener(CloudClientListener cloudClientListener) { this.listeners.add(new CloudClientListenerAdapter(cloudClientListener)); } @Override public void removeCloudClientListener(CloudClientListener cloudClientListener) { // create a copy to avoid concurrent modification exceptions List adapters = new ArrayList<>(this.listeners); for (CloudClientListenerAdapter adapter : adapters) { if (adapter.getCloudClientListenerAdapted() == cloudClientListener) { this.listeners.remove(adapter); break; } } } // -------------------------------------------------------------------- // // CloudClient API // // -------------------------------------------------------------------- @Override public boolean isConnected() { return this.dataService.isConnected(); } @Override public int publish(String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain); } @Override public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) throws KuraException { return publish(deviceId, appTopic, payload, qos, retain, 5); } @Override public int publish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority); } @Override public int publish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { byte[] appPayload = this.cloudServiceImpl.encodePayload(payload); return publish(deviceId, appTopic, appPayload, qos, retain, priority); } @Override public int publish(String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); return publish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority); } @Override public int publish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { boolean isControl = false; String fullTopic = encodeTopic(deviceId, appTopic, isControl); return this.dataService.publish(fullTopic, payload, qos, retain, priority); } @Override public int controlPublish(String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); return controlPublish(options.getTopicClientIdToken(), appTopic, payload, qos, retain, priority); } @Override public int controlPublish(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain, int priority) throws KuraException { byte[] appPayload = this.cloudServiceImpl.encodePayload(payload); return controlPublish(deviceId, appTopic, appPayload, qos, retain, priority); } @Override public int controlPublish(String deviceId, String appTopic, byte[] payload, int qos, boolean retain, int priority) throws KuraException { boolean isControl = true; String fullTopic = encodeTopic(deviceId, appTopic, isControl); return this.dataService.publish(fullTopic, payload, qos, retain, priority); } @Override public void subscribe(String appTopic, int qos) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); subscribe(options.getTopicClientIdToken(), appTopic, qos); } @Override public void subscribe(String deviceId, String appTopic, int qos) throws KuraException { boolean isControl = false; String fullTopic = encodeTopic(deviceId, appTopic, isControl); this.dataService.subscribe(fullTopic, qos); } @Override public void controlSubscribe(String appTopic, int qos) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); controlSubscribe(options.getTopicClientIdToken(), appTopic, qos); } @Override public void controlSubscribe(String deviceId, String appTopic, int qos) throws KuraException { boolean isControl = true; String fullTopic = encodeTopic(deviceId, appTopic, isControl); this.dataService.subscribe(fullTopic, qos); } @Override public void unsubscribe(String appTopic) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); unsubscribe(options.getTopicClientIdToken(), appTopic); } @Override public void unsubscribe(String deviceId, String appTopic) throws KuraException { boolean isControl = false; String fullTopic = encodeTopic(deviceId, appTopic, isControl); this.dataService.unsubscribe(fullTopic); } @Override public void controlUnsubscribe(String appTopic) throws KuraException { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); controlUnsubscribe(options.getTopicClientIdToken(), appTopic); } @Override public void controlUnsubscribe(String deviceId, String appTopic) throws KuraException { boolean isControl = true; String fullTopic = encodeTopic(deviceId, appTopic, isControl); this.dataService.unsubscribe(fullTopic); } @Override public List getUnpublishedMessageIds() throws KuraException { String topicRegex = getAppTopicRegex(); return this.dataService.getUnpublishedMessageIds(topicRegex); } @Override public List getInFlightMessageIds() throws KuraException { String topicRegex = getAppTopicRegex(); return this.dataService.getInFlightMessageIds(topicRegex); } @Override public List getDroppedInFlightMessageIds() throws KuraException { String topicRegex = getAppTopicRegex(); return this.dataService.getDroppedInFlightMessageIds(topicRegex); } // -------------------------------------------------------------------- // // CloudCallbackHandler API // // -------------------------------------------------------------------- @Override public void onMessageArrived(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) { for (CloudClientListener listener : this.listeners) { listener.onMessageArrived(deviceId, appTopic, payload, qos, retain); } } @Override public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload payload, int qos, boolean retain) { for (CloudClientListener listener : this.listeners) { listener.onControlMessageArrived(deviceId, appTopic, payload, qos, retain); } } @Override public void onMessageConfirmed(int pubId, String appTopic) { for (CloudClientListener listener : this.listeners) { listener.onMessageConfirmed(pubId, appTopic); } } @Override public void onMessagePublished(int pubId, String appTopic) { for (CloudClientListener listener : this.listeners) { listener.onMessagePublished(pubId, appTopic); } } @Override public void onConnectionEstablished() { for (CloudClientListener listener : this.listeners) { listener.onConnectionEstablished(); } } @Override public void onConnectionLost() { for (CloudClientListener listener : this.listeners) { listener.onConnectionLost(); } } // ---------------------------------------------------------------- // // Private methods // // ---------------------------------------------------------------- private String encodeTopic(String deviceId, String appTopic, boolean isControl) { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); StringBuilder sb = new StringBuilder(); if (isControl) { sb.append(options.getTopicControlPrefix()).append(options.getTopicSeparator()); } sb.append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(deviceId) .append(options.getTopicSeparator()).append(this.applicationId); if (appTopic != null && !appTopic.isEmpty()) { sb.append(options.getTopicSeparator()).append(appTopic); } return sb.toString(); } private String getAppTopicRegex() { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); StringBuilder sb = new StringBuilder(); // String regexExample = "^(\\$EDC/)?eurotech/.+/conf-v1(/.+)?"; // Optional control prefix sb.append("^(") // .append(options.getTopicControlPrefix()) .append("\\$EDC").append(options.getTopicSeparator()).append(")?") .append(options.getTopicAccountToken()).append(options.getTopicSeparator()).append(".+") // Any device // ID .append(options.getTopicSeparator()).append(this.applicationId).append("(/.+)?"); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudClientListenerAdapter.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import org.eclipse.kura.cloud.CloudClientListener; import org.eclipse.kura.message.KuraPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class to invoke CloudClientListeners catching and ignoring possible raised exceptions. */ public class CloudClientListenerAdapter implements CloudClientListener { private static final String IGNORED_ERROR_NOTIFYING = "IGNORED - Error notifying "; private static final Logger s_logger = LoggerFactory.getLogger(CloudClientListenerAdapter.class); private final CloudClientListener m_listener; CloudClientListenerAdapter(CloudClientListener listener) { this.m_listener = listener; } public CloudClientListener getCloudClientListenerAdapted() { return this.m_listener; } @Override public void onControlMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) { try { this.m_listener.onControlMessageArrived(deviceId, appTopic, msg, qos, retain); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onControlMessageArrived", e); } } @Override public void onMessageArrived(String deviceId, String appTopic, KuraPayload msg, int qos, boolean retain) { try { this.m_listener.onMessageArrived(deviceId, appTopic, msg, qos, retain); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onMessageArrived", e); } } @Override public void onConnectionLost() { try { this.m_listener.onConnectionLost(); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onConnectionLost", e); } } @Override public void onConnectionEstablished() { try { this.m_listener.onConnectionEstablished(); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onConnectionEstablished", e); } } @Override public void onMessageConfirmed(int messageId, String appTopic) { try { this.m_listener.onMessageConfirmed(messageId, appTopic); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onMessageConfirmed", e); } } @Override public void onMessagePublished(int messageId, String appTopic) { try { this.m_listener.onMessagePublished(messageId, appTopic); } catch (Exception e) { s_logger.error(IGNORED_ERROR_NOTIFYING + this.m_listener + " for onMessagePublished", e); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.io.IOException; /** * Common interface for the PayloadEncoders */ public interface CloudPayloadEncoder { public byte[] getBytes() throws IOException; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadGZipEncoder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.io.IOException; import org.eclipse.kura.core.util.GZipUtil; public class CloudPayloadGZipEncoder implements CloudPayloadEncoder { private final CloudPayloadEncoder decorated; public CloudPayloadGZipEncoder(CloudPayloadEncoder decorated) { this.decorated = decorated; } @Override public byte[] getBytes() throws IOException { byte[] source = this.decorated.getBytes(); byte[] compressed = GZipUtil.compress(source); // Return gzip compressed data only if shorter than uncompressed one return compressed.length < source.length ? compressed : source; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadProtoBufDecoderImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.io.IOException; import java.util.Date; import org.eclipse.kura.KuraInvalidMessageException; import org.eclipse.kura.KuraInvalidMetricTypeException; import org.eclipse.kura.core.message.protobuf.KuraPayloadProto; import org.eclipse.kura.core.util.GZipUtil; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraPosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; public class CloudPayloadProtoBufDecoderImpl { private static final Logger s_logger = LoggerFactory.getLogger(CloudPayloadProtoBufDecoderImpl.class); private byte[] m_bytes; public CloudPayloadProtoBufDecoderImpl(byte[] bytes) { this.m_bytes = bytes; } /** * Factory method to build an KuraPayload instance from a byte array. * * @param bytes * @return * @throws InvalidProtocolBufferException * @throws IOException */ public KuraPayload buildFromByteArray() throws KuraInvalidMessageException, IOException { // Check if a compressed payload and try to decompress it if (GZipUtil.isCompressed(this.m_bytes)) { try { this.m_bytes = GZipUtil.decompress(this.m_bytes); } catch (IOException e) { s_logger.info("Decompression failed"); // do not rethrow the exception here as isCompressed may return some false positives } } // build the KuraPayloadProto.KuraPayload KuraPayloadProto.KuraPayload protoMsg = null; try { protoMsg = KuraPayloadProto.KuraPayload.parseFrom(this.m_bytes); } catch (InvalidProtocolBufferException ipbe) { throw new KuraInvalidMessageException(ipbe); } // build the KuraPayload KuraPayload kuraMsg = new KuraPayload(); // set the timestamp if (protoMsg.hasTimestamp()) { kuraMsg.setTimestamp(new Date(protoMsg.getTimestamp())); } // set the position if (protoMsg.hasPosition()) { kuraMsg.setPosition(buildFromProtoBuf(protoMsg.getPosition())); } // set the metrics for (int i = 0; i < protoMsg.getMetricCount(); i++) { String name = protoMsg.getMetric(i).getName(); try { Object value = getProtoKuraMetricValue(protoMsg.getMetric(i), protoMsg.getMetric(i).getType()); kuraMsg.addMetric(name, value); } catch (KuraInvalidMetricTypeException ihte) { s_logger.warn("During deserialization, ignoring metric named: {}. Unrecognized value type: {}", name, protoMsg.getMetric(i).getType(), ihte); } } // set the body if (protoMsg.hasBody()) { kuraMsg.setBody(protoMsg.getBody().toByteArray()); } return kuraMsg; } private KuraPosition buildFromProtoBuf(KuraPayloadProto.KuraPayload.KuraPosition protoPosition) { KuraPosition position = new KuraPosition(); if (protoPosition.hasLatitude()) { position.setLatitude(protoPosition.getLatitude()); } if (protoPosition.hasLongitude()) { position.setLongitude(protoPosition.getLongitude()); } if (protoPosition.hasAltitude()) { position.setAltitude(protoPosition.getAltitude()); } if (protoPosition.hasPrecision()) { position.setPrecision(protoPosition.getPrecision()); } if (protoPosition.hasHeading()) { position.setHeading(protoPosition.getHeading()); } if (protoPosition.hasSpeed()) { position.setSpeed(protoPosition.getSpeed()); } if (protoPosition.hasSatellites()) { position.setSatellites(protoPosition.getSatellites()); } if (protoPosition.hasStatus()) { position.setStatus(protoPosition.getStatus()); } if (protoPosition.hasTimestamp()) { position.setTimestamp(new Date(protoPosition.getTimestamp())); } return position; } private Object getProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric metric, KuraPayloadProto.KuraPayload.KuraMetric.ValueType type) throws KuraInvalidMetricTypeException { switch (type) { case DOUBLE: return metric.getDoubleValue(); case FLOAT: return metric.getFloatValue(); case INT64: return metric.getLongValue(); case INT32: return metric.getIntValue(); case BOOL: return metric.getBoolValue(); case STRING: return metric.getStringValue(); case BYTES: ByteString bs = metric.getBytesValue(); return bs.toByteArray(); default: throw new KuraInvalidMetricTypeException(type); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPayloadProtoBufEncoderImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.io.IOException; import java.util.Map; import org.eclipse.kura.KuraInvalidMetricTypeException; import org.eclipse.kura.core.message.protobuf.KuraPayloadProto; import org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraPosition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; /** * Encodes an KuraPayload class using the Google ProtoBuf binary format. */ public class CloudPayloadProtoBufEncoderImpl implements CloudPayloadEncoder { private static final Logger logger = LoggerFactory.getLogger(CloudPayloadProtoBufEncoderImpl.class); private final KuraPayload kuraPayload; public CloudPayloadProtoBufEncoderImpl(KuraPayload kuraPayload) { this.kuraPayload = kuraPayload; } /** * Conversion method to serialize an KuraPayload instance into a byte array. * * @return */ @Override public byte[] getBytes() throws IOException { // Build the message KuraPayloadProto.KuraPayload.Builder protoMsg = KuraPayloadProto.KuraPayload.newBuilder(); // set the timestamp if (this.kuraPayload.getTimestamp() != null) { protoMsg.setTimestamp(this.kuraPayload.getTimestamp().getTime()); } // set the position if (this.kuraPayload.getPosition() != null) { protoMsg.setPosition(buildPositionProtoBuf()); } // set the metrics for (final Map.Entry entry : this.kuraPayload.metrics().entrySet()) { final String name = entry.getKey(); final Object value = entry.getValue(); // build a metric try { KuraMetric.Builder metricB = KuraMetric.newBuilder(); metricB.setName(name); boolean result = setProtoKuraMetricValue(metricB, value); if (result) { // add it to the message protoMsg.addMetric(metricB); } } catch (KuraInvalidMetricTypeException e) { logger.error("During serialization, ignoring metric named: {}. Unrecognized value type: {}.", name, value != null ? value.getClass().getName() : ""); throw new RuntimeException(e); } } // set the body if (this.kuraPayload.getBody() != null) { protoMsg.setBody(ByteString.copyFrom(this.kuraPayload.getBody())); } return protoMsg.build().toByteArray(); } // // Helper methods to convert the KuraMetrics // private KuraPayloadProto.KuraPayload.KuraPosition buildPositionProtoBuf() { KuraPayloadProto.KuraPayload.KuraPosition.Builder protoPos = KuraPayloadProto.KuraPayload.KuraPosition .newBuilder(); KuraPosition position = this.kuraPayload.getPosition(); if (position.getLatitude() != null) { protoPos.setLatitude(position.getLatitude()); } if (position.getLongitude() != null) { protoPos.setLongitude(position.getLongitude()); } if (position.getAltitude() != null) { protoPos.setAltitude(position.getAltitude()); } if (position.getPrecision() != null) { protoPos.setPrecision(position.getPrecision()); } if (position.getHeading() != null) { protoPos.setHeading(position.getHeading()); } if (position.getSpeed() != null) { protoPos.setSpeed(position.getSpeed()); } if (position.getTimestamp() != null) { protoPos.setTimestamp(position.getTimestamp().getTime()); } if (position.getSatellites() != null) { protoPos.setSatellites(position.getSatellites()); } if (position.getStatus() != null) { protoPos.setStatus(position.getStatus()); } return protoPos.build(); } private static boolean setProtoKuraMetricValue(KuraPayloadProto.KuraPayload.KuraMetric.Builder metric, Object o) throws KuraInvalidMetricTypeException { if (o instanceof String) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.STRING); metric.setStringValue((String) o); } else if (o instanceof Double) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE); metric.setDoubleValue((Double) o); } else if (o instanceof Integer) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT32); metric.setIntValue((Integer) o); } else if (o instanceof Float) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.FLOAT); metric.setFloatValue((Float) o); } else if (o instanceof Long) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.INT64); metric.setLongValue((Long) o); } else if (o instanceof Boolean) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BOOL); metric.setBoolValue((Boolean) o); } else if (o instanceof byte[]) { metric.setType(KuraPayloadProto.KuraPayload.KuraMetric.ValueType.BYTES); metric.setBytesValue(ByteString.copyFrom((byte[]) o)); } else if (o == null) { logger.warn("Received a metric with a null value!"); return false; } else { throw new KuraInvalidMetricTypeException(o.getClass().getName()); } return true; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudPublisherDeliveryListener.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; public interface CloudPublisherDeliveryListener { public void onMessageConfirmed(String messageId, String topic); } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import static org.eclipse.kura.cloud.CloudPayloadEncoding.KURA_PROTOBUF; import static org.eclipse.kura.cloud.CloudPayloadEncoding.SIMPLE_JSON; import static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID; import static org.eclipse.kura.core.message.MessageConstants.APP_ID; import static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC; import static org.eclipse.kura.core.message.MessageConstants.CONTROL; import static org.eclipse.kura.core.message.MessageConstants.FULL_TOPIC; import static org.eclipse.kura.core.message.MessageConstants.PRIORITY; import static org.eclipse.kura.core.message.MessageConstants.QOS; import static org.eclipse.kura.core.message.MessageConstants.RETAIN; import static org.osgi.framework.Constants.SERVICE_PID; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraInvalidMessageException; import org.eclipse.kura.certificate.CertificatesService; import org.eclipse.kura.cloud.CloudClient; import org.eclipse.kura.cloud.CloudConnectionEstablishedEvent; import org.eclipse.kura.cloud.CloudConnectionLostEvent; import org.eclipse.kura.cloud.CloudPayloadEncoding; import org.eclipse.kura.cloud.CloudPayloadProtoBufDecoder; import org.eclipse.kura.cloud.CloudPayloadProtoBufEncoder; import org.eclipse.kura.cloud.CloudService; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.cloud.publisher.NotificationPublisherImpl; import org.eclipse.kura.core.cloud.subscriber.CloudSubscriptionRecord; import org.eclipse.kura.core.data.DataServiceImpl; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.message.KuraApplicationTopic; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.net.NetworkService; import org.eclipse.kura.net.status.NetworkInterfaceStatus; import org.eclipse.kura.net.status.NetworkInterfaceType; import org.eclipse.kura.net.status.NetworkStatusService; import org.eclipse.kura.net.status.modem.ModemInterfaceStatus; import org.eclipse.kura.net.status.modem.Sim; import org.eclipse.kura.position.PositionLockedEvent; import org.eclipse.kura.position.PositionService; import org.eclipse.kura.security.tamper.detection.TamperDetectionService; import org.eclipse.kura.security.tamper.detection.TamperEvent; import org.eclipse.kura.system.SystemAdminService; import org.eclipse.kura.system.SystemService; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudServiceImpl implements CloudService, DataServiceListener, ConfigurableComponent, EventHandler, CloudPayloadProtoBufEncoder, CloudPayloadProtoBufDecoder, RequestHandlerRegistry, CloudConnectionManager, CloudEndpoint { private static final Logger logger = LoggerFactory.getLogger(CloudServiceImpl.class); private static final String TOPIC_BA_APP = "BA"; private static final String TOPIC_MQTT_APP = "MQTT"; private static final String CONNECTION_EVENT_PID_PROPERTY_KEY = "cloud.service.pid"; private static final String SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE = "Cannot setup cloud service connection"; private static final String NOTIFICATION_PUBLISHER_PID = "org.eclipse.kura.cloud.publisher.CloudNotificationPublisher"; private static final String KURA_PAYLOAD = "KuraPayload"; static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL = "org/osgi/service/deployment/INSTALL"; static final String EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL = "org/osgi/service/deployment/UNINSTALL"; private static final int NUM_CONCURRENT_CALLBACKS = 2; private static ExecutorService callbackExecutor = Executors.newFixedThreadPool(NUM_CONCURRENT_CALLBACKS); private ComponentContext ctx; private CloudServiceOptions options; private DataService dataService; private SystemService systemService; private SystemAdminService systemAdminService; private Optional networkService = Optional.empty(); private Optional positionService = Optional.empty(); private EventAdmin eventAdmin; private CertificatesService certificatesService; private Unmarshaller jsonUnmarshaller; private Marshaller jsonMarshaller; private Optional networkStatusService = Optional.empty(); // use a synchronized implementation for the list private final List cloudClients; private final Set registeredCloudConnectionListeners; private final Set registeredCloudPublisherDeliveryListeners; private final Set registeredCloudDeliveryListeners; private final Map> registeredSubscribers; // package visibility for LyfeCyclePayloadBuilder String imei; String iccid; String imsi; String rssi; String modemFwVer; private boolean subscribed; private final AtomicInteger messageId; private ServiceRegistration cloudServiceRegistration; private final Map registeredRequestHandlers; private ServiceRegistration notificationPublisherRegistration; private final CloudNotificationPublisher notificationPublisher; private final Set tamperDetectionServices = new HashSet<>(); private String ownPid; private ScheduledFuture scheduledBirthPublisherFuture; private final ScheduledExecutorService scheduledBirthPublisher = Executors.newSingleThreadScheduledExecutor(); private final AtomicBoolean shouldPublishDelayedBirth = new AtomicBoolean(); public CloudServiceImpl() { this.cloudClients = new CopyOnWriteArrayList<>(); this.messageId = new AtomicInteger(); this.registeredRequestHandlers = new HashMap<>(); this.registeredSubscribers = new ConcurrentHashMap<>(); this.registeredCloudConnectionListeners = new CopyOnWriteArraySet<>(); this.registeredCloudPublisherDeliveryListeners = new CopyOnWriteArraySet<>(); this.registeredCloudDeliveryListeners = new CopyOnWriteArraySet<>(); this.notificationPublisher = new NotificationPublisherImpl(this); } // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setDataService(DataService dataService) { this.dataService = dataService; } public void unsetDataService(DataService dataService) { if (this.dataService != null && this.dataService.equals(dataService)) { this.dataService = null; } } public DataService getDataService() { return this.dataService; } public void setSystemAdminService(SystemAdminService systemAdminService) { this.systemAdminService = systemAdminService; } public void unsetSystemAdminService(SystemAdminService systemAdminService) { if (this.systemAdminService != null && this.systemAdminService.equals(systemAdminService)) { this.systemAdminService = null; } } public SystemAdminService getSystemAdminService() { return this.systemAdminService; } public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { if (this.systemService != null && this.systemService.equals(systemService)) { this.systemService = null; } } public SystemService getSystemService() { return this.systemService; } public void setNetworkService(NetworkService networkService) { this.networkService = Optional.of(networkService); } public void unsetNetworkService(NetworkService networkService) { if (this.networkService.isPresent() && this.networkService.get().equals(networkService)) { this.networkService = Optional.empty(); } } public Optional getNetworkService() { return this.networkService; } public void setPositionService(PositionService positionService) { this.positionService = Optional.of(positionService); } public void unsetPositionService(PositionService positionService) { if (this.positionService.isPresent() && this.positionService.get().equals(positionService)) { this.positionService = Optional.empty(); } } public Optional getPositionService() { return this.positionService; } public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void unsetEventAdmin(EventAdmin eventAdmin) { if (this.eventAdmin != null && this.eventAdmin.equals(eventAdmin)) { this.eventAdmin = null; } } public void setJsonUnmarshaller(Unmarshaller jsonUnmarshaller) { this.jsonUnmarshaller = jsonUnmarshaller; } public void unsetJsonUnmarshaller(Unmarshaller jsonUnmarshaller) { if (this.jsonUnmarshaller != null && this.jsonUnmarshaller.equals(jsonUnmarshaller)) { this.jsonUnmarshaller = null; } } public void setJsonMarshaller(Marshaller jsonMarshaller) { this.jsonMarshaller = jsonMarshaller; } public void unsetJsonMarshaller(Marshaller jsonMarshaller) { if (this.jsonMarshaller != null && this.jsonMarshaller.equals(jsonMarshaller)) { this.jsonMarshaller = null; } } public void setTamperDetectionService(final TamperDetectionService tamperDetectionService) { synchronized (this.tamperDetectionServices) { this.tamperDetectionServices.add(tamperDetectionService); } } public void unsetTamperDetectionService(final TamperDetectionService tamperDetectionService) { if (!this.tamperDetectionServices.isEmpty() && this.tamperDetectionServices.contains(tamperDetectionService)) { synchronized (this.tamperDetectionServices) { this.tamperDetectionServices.remove(tamperDetectionService); } } } public void setNetworkStatusService(NetworkStatusService networkStatusService) { this.networkStatusService = Optional.of(networkStatusService); } public void unsetNetworkStatusService(NetworkStatusService networkStatusService) { if (this.networkStatusService.isPresent() && this.networkStatusService.get().equals(networkStatusService)) { this.networkStatusService = Optional.empty(); } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext, Map properties) { this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("activate {}...", this.ownPid); // // save the bundle context and the properties this.ctx = componentContext; this.options = new CloudServiceOptions(properties, this.systemService); // // install event listener for GPS locked event Dictionary props = new Hashtable<>(); String[] eventTopics = { PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC, TamperEvent.TAMPER_EVENT_TOPIC, EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL, EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL }; props.put(EventConstants.EVENT_TOPIC, eventTopics); this.cloudServiceRegistration = this.ctx.getBundleContext().registerService(EventHandler.class.getName(), this, props); this.dataService.addDataServiceListener(this); Dictionary notificationPublisherProps = new Hashtable<>(); notificationPublisherProps.put(KURA_SERVICE_PID, NOTIFICATION_PUBLISHER_PID); notificationPublisherProps.put(SERVICE_PID, NOTIFICATION_PUBLISHER_PID); this.notificationPublisherRegistration = this.ctx.getBundleContext().registerService( CloudNotificationPublisher.class.getName(), this.notificationPublisher, notificationPublisherProps); // // Usually the cloud connection is setup in the // onConnectionEstablished callback. // Since the callback may be lost if we are activated // too late (the DataService is already connected) we // setup the cloud connection here. if (isConnected()) { logger.warn("DataService is already connected. Publish BIRTH certificate"); try { setupCloudConnection(true); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE, e); } } } public void updated(Map properties) { logger.info("updated {}...", properties.get(ConfigurationService.KURA_SERVICE_PID)); // Update properties and re-publish Birth certificate this.options = new CloudServiceOptions(properties, this.systemService); if (isConnected()) { try { setupCloudConnection(false); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE); } } } protected void deactivate(ComponentContext componentContext) { logger.info("deactivate {}...", componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID)); if (isConnected()) { try { publishDisconnectCertificate(); } catch (KuraException e) { logger.warn("Cannot publish disconnect certificate"); } } this.dataService.removeDataServiceListener(this); // no need to release the cloud clients as the updated app // certificate is already published due the missing dependency // we only need to empty our CloudClient list this.cloudClients.clear(); this.dataService = null; this.systemService = null; this.systemAdminService = null; this.networkService = Optional.empty(); this.positionService = Optional.empty(); this.eventAdmin = null; this.certificatesService = null; this.cloudServiceRegistration.unregister(); this.notificationPublisherRegistration.unregister(); } @Override public void handleEvent(Event event) { String topic = event.getTopic(); if (PositionLockedEvent.POSITION_LOCKED_EVENT_TOPIC.contains(topic)) { handlePositionLockedEvent(); return; } if (TamperEvent.TAMPER_EVENT_TOPIC.equals(topic) && this.dataService.isConnected() && this.options.getRepubBirthCertOnTamperEvent()) { logger.debug("CloudServiceImpl: received tamper event, publishing BIRTH."); tryPublishBirthCertificate(false); return; } if ((EVENT_TOPIC_DEPLOYMENT_ADMIN_INSTALL.equals(topic) || EVENT_TOPIC_DEPLOYMENT_ADMIN_UNINSTALL.equals(topic)) && this.dataService.isConnected()) { logger.debug("CloudServiceImpl: received install/uninstall event, publishing BIRTH."); tryPublishBirthCertificate(false); } } private void tryPublishBirthCertificate(boolean isNewConnection) { try { publishBirthCertificate(isNewConnection); } catch (KuraException e) { logger.warn("Cannot publish birth certificate", e); } } private void handlePositionLockedEvent() { // if we get a position locked event, // republish the birth certificate only if we are configured to logger.info("Handling PositionLockedEvent"); if (this.dataService.isConnected() && this.options.getRepubBirthCertOnGpsLock()) { tryPublishBirthCertificate(false); } } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public CloudClient newCloudClient(String applicationId) throws KuraException { // create new instance CloudClientImpl cloudClient = new CloudClientImpl(applicationId, this.dataService, this); this.cloudClients.add(cloudClient); // publish updated birth certificate with list of active apps if (isConnected()) { publishAppCertificate(); } // return return cloudClient; } @Override public String[] getCloudApplicationIdentifiers() { List appIds = new ArrayList<>(); for (CloudClientImpl cloudClient : this.cloudClients) { appIds.add(cloudClient.getApplicationId()); } for (Entry entry : this.registeredRequestHandlers.entrySet()) { appIds.add(entry.getKey()); } return appIds.toArray(new String[0]); } @Override public boolean isConnected() { return this.dataService != null && this.dataService.isConnected(); } // ---------------------------------------------------------------- // // Package APIs // // ---------------------------------------------------------------- public CloudServiceOptions getCloudServiceOptions() { return this.options; } public void removeCloudClient(CloudClientImpl cloudClient) { // remove the client this.cloudClients.remove(cloudClient); // publish updated birth certificate with updated list of active apps if (isConnected()) { publishAppCertificate(); } } public byte[] encodePayload(KuraPayload payload) throws KuraException { byte[] bytes; CloudPayloadEncoding preferencesEncoding = this.options.getPayloadEncoding(); if (preferencesEncoding == KURA_PROTOBUF) { bytes = encodeProtobufPayload(payload); } else if (preferencesEncoding == SIMPLE_JSON) { bytes = encodeJsonPayload(payload); } else { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD); } return bytes; } // ---------------------------------------------------------------- // // DataServiceListener API // // ---------------------------------------------------------------- @Override public void onConnectionEstablished() { try { setupCloudConnection(true); } catch (KuraException e) { logger.warn(SETUP_CLOUD_SERVICE_CONNECTION_ERROR_MESSAGE); } this.registeredSubscribers.keySet().forEach(this::subscribe); postConnectionStateChangeEvent(true); this.cloudClients.forEach(CloudClientImpl::onConnectionEstablished); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished); } private void setupDeviceSubscriptions(boolean subscribe) throws KuraException { StringBuilder sbDeviceSubscription = new StringBuilder(); sbDeviceSubscription.append(this.options.getTopicControlPrefix()) .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicAccountToken()) .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicClientIdToken()) .append(CloudServiceOptions.getTopicSeparator()).append(CloudServiceOptions.getTopicWildCard()); // restore or remove default subscriptions if (subscribe) { this.dataService.subscribe(sbDeviceSubscription.toString(), 1); } else { this.dataService.unsubscribe(sbDeviceSubscription.toString()); } } @Override public void onDisconnecting() { // publish disconnect certificate try { publishDisconnectCertificate(); } catch (KuraException e) { logger.warn("Cannot publish disconnect certificate"); } } @Override public void onDisconnected() { // raise event postConnectionStateChangeEvent(false); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected); } @Override public void onConnectionLost(Throwable cause) { // raise event postConnectionStateChangeEvent(false); this.cloudClients.forEach(CloudClientImpl::onConnectionLost); this.registeredCloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { logger.info("Message arrived on topic: {}", topic); // notify listeners KuraTopicImpl kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix()); if (TOPIC_MQTT_APP.equals(kuraTopic.getApplicationId()) || TOPIC_BA_APP.equals(kuraTopic.getApplicationId())) { logger.info("Ignoring feedback message from {}", topic); } else { KuraPayload kuraPayload = encodeKuraPayload(topic, payload); try { if (this.options.getTopicControlPrefix().equals(kuraTopic.getPrefix())) { boolean validMessage = isValidMessage(kuraTopic, kuraPayload); if (validMessage) { dispatchControlMessage(qos, retained, kuraTopic, kuraPayload); } else { logger.warn("Message verification failed! Not valid signature or message not signed."); } } else { dispatchDataMessage(qos, retained, kuraTopic, kuraPayload); } } catch (Exception e) { logger.error("Error during CloudClientListener notification.", e); } } } private KuraPayload encodeKuraPayload(String topic, byte[] payload) { KuraPayload kuraPayload = null; if (this.options.getPayloadEncoding() == SIMPLE_JSON) { try { kuraPayload = createKuraPayloadFromJson(payload); } catch (KuraException e) { logger.warn("Error creating Kura Payload from Json", e); } } else if (this.options.getPayloadEncoding() == KURA_PROTOBUF) { kuraPayload = createKuraPayloadFromProtoBuf(topic, payload); } return kuraPayload; } private void dispatchControlMessage(int qos, boolean retained, KuraTopicImpl kuraTopic, KuraPayload kuraPayload) { String applicationId = kuraTopic.getApplicationId(); RequestHandler cloudlet = this.registeredRequestHandlers.get(applicationId); if (cloudlet != null) { StringBuilder sb = new StringBuilder(applicationId).append("/").append("REPLY"); if (kuraTopic.getApplicationTopic().startsWith(sb.toString())) { // Ignore replies return; } callbackExecutor.submit(new MessageHandlerCallable(cloudlet, applicationId, kuraTopic.getApplicationTopic(), kuraPayload, this)); } this.cloudClients.stream() .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId())) .forEach(cloudClient -> cloudClient.onControlMessageArrived(kuraTopic.getDeviceId(), kuraTopic.getApplicationTopic(), kuraPayload, qos, retained)); Map properties = new HashMap<>(); properties.put("deviceId", kuraTopic.getDeviceId()); properties.put("appTopic", kuraTopic.getApplicationTopic()); KuraMessage receivedMessage = new KuraMessage(kuraPayload, properties); this.registeredSubscribers.entrySet().stream() .filter(cloudSubscriberEntry -> cloudSubscriberEntry.getKey().matches(kuraTopic.getFullTopic())) .forEach(e -> dispatchMessage(receivedMessage, e.getValue())); } private void dispatchDataMessage(int qos, boolean retained, KuraTopicImpl kuraTopic, KuraPayload kuraPayload) { this.cloudClients.stream() .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId())) .forEach(cloudClient -> cloudClient.onMessageArrived(kuraTopic.getDeviceId(), kuraTopic.getApplicationTopic(), kuraPayload, qos, retained)); Map properties = new HashMap<>(); properties.put("deviceId", kuraTopic.getDeviceId()); properties.put("appTopic", kuraTopic.getApplicationTopic()); KuraMessage receivedMessage = new KuraMessage(kuraPayload, properties); this.registeredSubscribers.entrySet().stream() .filter(cloudSubscriberEntry -> cloudSubscriberEntry.getKey().matches(kuraTopic.getFullTopic())) .forEach(e -> dispatchMessage(receivedMessage, e.getValue())); } private static void dispatchMessage(final KuraMessage message, final List listeners) { for (final CloudSubscriberListener listener : listeners) { try { listener.onMessageArrived(message); } catch (final Exception e) { logger.warn("unhandled exception in CloudSubscriberListener", e); } } } private boolean isValidMessage(KuraApplicationTopic kuraTopic, KuraPayload kuraPayload) { if (this.certificatesService == null) { ServiceReference sr = this.ctx.getBundleContext() .getServiceReference(CertificatesService.class); if (sr != null) { this.certificatesService = this.ctx.getBundleContext().getService(sr); } } boolean validMessage = false; if (this.certificatesService == null || this.certificatesService.verifySignature(kuraTopic, kuraPayload)) { validMessage = true; } return validMessage; } @Override public void onMessagePublished(int messageId, String topic) { synchronized (this.messageId) { if (this.messageId.get() != -1 && this.messageId.get() == messageId) { this.messageId.set(-1); this.messageId.notifyAll(); return; } } // notify listeners KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix()); this.cloudClients.stream() .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId())) .collect(Collectors.toList()) .forEach(cloudClient -> cloudClient.onMessagePublished(messageId, kuraTopic.getApplicationTopic())); } @Override public void onMessageConfirmed(int messageId, String topic) { synchronized (this.messageId) { if (this.messageId.get() != -1 && this.messageId.get() == messageId) { this.messageId.set(-1); this.messageId.notifyAll(); return; } } // notify listeners KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic, this.options.getTopicControlPrefix()); this.cloudClients.stream() .filter(cloudClient -> cloudClient.getApplicationId().equals(kuraTopic.getApplicationId())) .collect(Collectors.toList()) .forEach(cloudClient -> cloudClient.onMessageConfirmed(messageId, kuraTopic.getApplicationTopic())); this.registeredCloudPublisherDeliveryListeners .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId), topic)); this.registeredCloudDeliveryListeners .forEach(deliveryListener -> deliveryListener.onMessageConfirmed(String.valueOf(messageId))); } // ---------------------------------------------------------------- // // CloudPayloadProtoBufEncoder API // // ---------------------------------------------------------------- @Override public byte[] getBytes(KuraPayload kuraPayload, boolean gzipped) throws KuraException { CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(kuraPayload); if (gzipped) { encoder = new CloudPayloadGZipEncoder(encoder); } byte[] bytes; try { bytes = encoder.getBytes(); return bytes; } catch (IOException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e); } } // ---------------------------------------------------------------- // // CloudPayloadProtoBufDecoder API // // ---------------------------------------------------------------- @Override public KuraPayload buildFromByteArray(byte[] payload) throws KuraException { CloudPayloadProtoBufDecoderImpl encoder = new CloudPayloadProtoBufDecoderImpl(payload); KuraPayload kuraPayload; try { kuraPayload = encoder.buildFromByteArray(); return kuraPayload; } catch (KuraInvalidMessageException | IOException e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, KURA_PAYLOAD, e); } } // ---------------------------------------------------------------- // // Birth and Disconnect Certificates // // ---------------------------------------------------------------- private void setupCloudConnection(boolean isNewConnection) throws KuraException { // assume we are not yet subscribed if (isNewConnection) { this.subscribed = false; } publishBirthCertificate(isNewConnection); // restore or remove default subscriptions if (this.options.getEnableDefaultSubscriptions()) { if (!this.subscribed) { setupDeviceSubscriptions(true); this.subscribed = true; } } else { logger.info("Default subscriptions are disabled in configuration"); if (this.subscribed) { setupDeviceSubscriptions(false); this.subscribed = false; } } } private void publishBirthCertificate(boolean isNewConnection) throws KuraException { if (isFrameworkStopping()) { logger.info("framework is stopping.. not republishing birth certificate"); return; } readModemProfile(); if (isNewConnection) { publishLifeCycleMessage(new LifecycleMessage(this.options, this).asBirthCertificateMessage()); } else { publishWithDelay(false); } } private void publishDisconnectCertificate() throws KuraException { publishLifeCycleMessage(new LifecycleMessage(this.options, this).asDisconnectCertificateMessage()); } private void publishAppCertificate() { if (isFrameworkStopping()) { logger.info("framework is stopping.. not republishing app certificate"); return; } publishWithDelay(true); } private void publishWithDelay(boolean isAppUpdate) { synchronized (this.shouldPublishDelayedBirth) { if (!isAppUpdate) { this.shouldPublishDelayedBirth.set(true); } if (Objects.nonNull(this.scheduledBirthPublisherFuture)) { this.scheduledBirthPublisherFuture.cancel(false); logger.debug("CloudServiceImpl: BIRTH message cache timer restarted."); } logger.debug("CloudServiceImpl: BIRTH message cached for 30s."); this.scheduledBirthPublisherFuture = this.scheduledBirthPublisher.schedule(this::publishDelayedMessage, 30L, TimeUnit.SECONDS); } } private void publishLifeCycleMessage(LifecycleMessage message) throws KuraException { // track the message ID and block until the message // has been published (i.e. written to the socket). synchronized (this.messageId) { this.messageId.set(-1); // add a timestamp to the message KuraPayload payload = message.getPayload(); payload.setTimestamp(new Date()); byte[] encodedPayload = encodePayload(payload); int id = this.dataService.publish(message.getTopic(), encodedPayload, message.getQos(), CloudServiceOptions.getLifeCycleMessageRetain(), CloudServiceOptions.getLifeCycleMessagePriority()); this.messageId.set(id); try { this.messageId.wait(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.info("Interrupted while waiting for the message to be published", e); } } } private void publishDelayedMessage() { synchronized (this.shouldPublishDelayedBirth) { try { if (this.shouldPublishDelayedBirth.get()) { publishLifeCycleMessage(new LifecycleMessage(this.options, this).asBirthCertificateMessage()); } else { publishLifeCycleMessage(new LifecycleMessage(this.options, this).asAppCertificateMessage()); } this.shouldPublishDelayedBirth.set(false); } catch (KuraException e) { logger.error("Error sending cached BIRTH/APP certificate.", e); } } } private byte[] encodeProtobufPayload(KuraPayload payload) throws KuraException { byte[] bytes = new byte[0]; if (payload == null) { return bytes; } CloudPayloadEncoder encoder = new CloudPayloadProtoBufEncoderImpl(payload); if (this.options.getEncodeGzip()) { encoder = new CloudPayloadGZipEncoder(encoder); } try { bytes = encoder.getBytes(); } catch (IOException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, KURA_PAYLOAD, e); } return bytes; } private byte[] encodeJsonPayload(KuraPayload payload) throws KuraException { return this.jsonMarshaller.marshal(payload).getBytes(StandardCharsets.UTF_8); } private KuraPayload createKuraPayloadFromJson(byte[] payload) throws KuraException { return this.jsonUnmarshaller.unmarshal(new String(payload), KuraPayload.class); } private KuraPayload createKuraPayloadFromProtoBuf(String topic, byte[] payload) { KuraPayload kuraPayload; try { // try to decode the message into an KuraPayload kuraPayload = new CloudPayloadProtoBufDecoderImpl(payload).buildFromByteArray(); } catch (Exception e) { // Wrap the received bytes payload into an KuraPayload logger.debug("Received message on topic {} that could not be decoded. Wrapping it into an KuraPayload.", topic); kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); } return kuraPayload; } private void postConnectionStateChangeEvent(final boolean isConnected) { final Map eventProperties = Collections.singletonMap(CONNECTION_EVENT_PID_PROPERTY_KEY, (String) this.ctx.getProperties().get(ConfigurationService.KURA_SERVICE_PID)); final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties) : new CloudConnectionLostEvent(eventProperties); this.eventAdmin.postEvent(event); } @Override public void registerRequestHandler(String appId, RequestHandler requestHandler) { this.registeredRequestHandlers.put(appId, requestHandler); if (isConnected()) { publishAppCertificate(); } } @Override public void unregister(String appId) { this.registeredRequestHandlers.remove(appId); if (isConnected()) { publishAppCertificate(); } } @Override public void connect() throws KuraConnectException { if (this.dataService != null) { this.dataService.connect(); } } @Override public void disconnect() { if (this.dataService != null) { this.dataService.disconnect(10); } } @Override public Map getInfo() { DataServiceImpl dataServiceImpl = (DataServiceImpl) this.dataService; return dataServiceImpl.getConnectionInfo(); } public String getNotificationPublisherPid() { return NOTIFICATION_PUBLISHER_PID; } public CloudNotificationPublisher getNotificationPublisher() { return this.notificationPublisher; } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.registeredCloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.registeredCloudConnectionListeners.remove(cloudConnectionListener); } public void registerCloudPublisherDeliveryListener(CloudPublisherDeliveryListener cloudPublisherDeliveryListener) { this.registeredCloudPublisherDeliveryListeners.add(cloudPublisherDeliveryListener); } public void unregisterCloudPublisherDeliveryListener( CloudPublisherDeliveryListener cloudPublisherDeliveryListener) { this.registeredCloudPublisherDeliveryListeners.remove(cloudPublisherDeliveryListener); } @Override public String publish(KuraMessage message) throws KuraException { Map messageProps = message.getProperties(); int qos = (Integer) messageProps.get(QOS.name()); boolean retain = (Boolean) messageProps.get(RETAIN.name()); int priority = (Integer) messageProps.get(PRIORITY.name()); String fullTopic = (String) messageProps.get(FULL_TOPIC.name()); if (isNull(fullTopic)) { String appId = (String) messageProps.get(APP_ID.name()); String appTopic = (String) messageProps.get(APP_TOPIC.name()); boolean isControl = (Boolean) messageProps.get(CONTROL.name()); String deviceId = CloudServiceOptions.getTopicClientIdToken(); fullTopic = encodeTopic(appId, deviceId, appTopic, isControl); } byte[] appPayload = encodePayload(message.getPayload()); int id = this.dataService.publish(fullTopic, appPayload, qos, retain, priority); if (qos == 0) { return null; } return String.valueOf(id); } @Override public void registerSubscriber(Map subscriptionProperties, CloudSubscriberListener subscriber) { String appId = (String) subscriptionProperties.get(APP_ID.name()); String appTopic = (String) subscriptionProperties.get(APP_TOPIC.name()); int qos = (Integer) subscriptionProperties.get(QOS.name()); boolean isControl = (Boolean) subscriptionProperties.get(CONTROL.name()); if (isNull(appId) || isNull(appTopic)) { return; } String fullTopic = encodeTopic(appId, CloudServiceOptions.getTopicClientIdToken(), appTopic, isControl); CloudSubscriptionRecord subscriptionRecord = new CloudSubscriptionRecord(fullTopic, qos); final List subscribers; synchronized (this) { subscribers = this.registeredSubscribers.compute(subscriptionRecord, (t, list) -> { if (list == null) { return new CopyOnWriteArrayList<>(Collections.singletonList(subscriber)); } list.add(subscriber); return list; }); } if (subscribers.size() == 1) { subscribe(subscriptionRecord); } } @Override public void unregisterSubscriber(CloudSubscriberListener subscriber) { final List toUnsubscribe = new ArrayList<>(); synchronized (this) { this.registeredSubscribers.entrySet().removeIf(e -> { final List subscribers = e.getValue(); subscribers.removeIf(s -> s == subscriber); if (subscribers.isEmpty()) { toUnsubscribe.add(e.getKey()); return true; } else { return false; } }); } for (final CloudSubscriptionRecord subscription : toUnsubscribe) { unsubscribe(subscription); } } private synchronized void subscribe(CloudSubscriptionRecord subscriptionRecord) { String fullTopic = subscriptionRecord.getTopic(); int qos = subscriptionRecord.getQos(); try { this.dataService.subscribe(fullTopic, qos); } catch (KuraException e) { logger.info("Failed to subscribe"); } } private synchronized void unsubscribe(CloudSubscriptionRecord subscriptionRecord) { String fullTopic = subscriptionRecord.getTopic(); try { this.dataService.unsubscribe(fullTopic); } catch (KuraException e) { logger.info("Failed to unsubscribe"); } } private String encodeTopic(String appId, String deviceId, String appTopic, boolean isControl) { StringBuilder sb = new StringBuilder(); if (isControl) { sb.append(this.options.getTopicControlPrefix()).append(CloudServiceOptions.getTopicSeparator()); } sb.append(CloudServiceOptions.getTopicAccountToken()).append(CloudServiceOptions.getTopicSeparator()) .append(deviceId).append(CloudServiceOptions.getTopicSeparator()).append(appId); if (appTopic != null && !appTopic.isEmpty()) { sb.append(CloudServiceOptions.getTopicSeparator()).append(appTopic); } return sb.toString(); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.registeredCloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.registeredCloudDeliveryListeners.remove(cloudDeliveryListener); } String getOwnPid() { return this.ownPid; } void withTamperDetectionServices(final Consumer> consumer) { synchronized (this.tamperDetectionServices) { consumer.accept(this.tamperDetectionServices); } } private boolean isFrameworkStopping() { try { final Bundle ownBundle = FrameworkUtil.getBundle(CloudServiceImpl.class); if (ownBundle == null) { return false; // not running in an OSGi framework? e.g. unit test } return ownBundle.getBundleContext().getBundle(0).getState() == Bundle.STOPPING; } catch (final Exception e) { logger.warn("unexpected exception while checking if framework is shutting down", e); return false; } } private void readModemProfile() { this.networkStatusService.ifPresent(statusService -> { List modemStatuses = getModemsStatuses(statusService); if (nonNull(modemStatuses) && !modemStatuses.isEmpty()) { readModemInfos(modemStatuses); } else { this.imei = null; this.iccid = null; this.imsi = null; this.rssi = null; this.modemFwVer = null; } }); } private List getModemsStatuses(NetworkStatusService networkStatusService) { List modemStatuses = new ArrayList<>(); try { List interfaceIds = networkStatusService.getInterfaceIds(); for (String interfaceId : interfaceIds) { Optional networkInterfaceStatus = networkStatusService .getNetworkStatus(interfaceId); networkInterfaceStatus.ifPresent(state -> { NetworkInterfaceType type = state.getType(); if (NetworkInterfaceType.MODEM.equals(type)) { modemStatuses.add((ModemInterfaceStatus) state); } }); } } catch (KuraException e) { logger.error("Error reading modem profile", e); } return modemStatuses; } private void readModemInfos(List modemStatuses) { Collections.sort(modemStatuses, Comparator.comparing(ModemInterfaceStatus::getConnectionStatus)); ModemInterfaceStatus modemStatus = modemStatuses.get(modemStatuses.size() - 1); Optional activeSim = Optional.empty(); List availableSims = modemStatus.getAvailableSims(); for (Sim sim : availableSims) { if (sim.isActive() && sim.isPrimary()) { activeSim = Optional.of(sim); } } this.iccid = null; this.imsi = null; activeSim.ifPresent(sim -> { this.iccid = sim.getIccid(); this.imsi = sim.getImsi(); }); this.imei = modemStatus.getSerialNumber(); this.rssi = String.valueOf(modemStatus.getSignalStrength()); this.modemFwVer = modemStatus.getFirmwareVersion(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/CloudServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.util.Map; import org.eclipse.kura.cloud.CloudPayloadEncoding; import org.eclipse.kura.system.SystemService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudServiceOptions { private static final Logger logger = LoggerFactory.getLogger(CloudServiceOptions.class); private static final String TOPIC_SEPARATOR = "/"; private static final String TOPIC_ACCOUNT_TOKEN = "#account-name"; private static final String TOPIC_CLIENT_ID_TOKEN = "#client-id"; private static final String TOPIC_BIRTH_SUFFIX = "MQTT/BIRTH"; private static final String TOPIC_DISCONNECT_SUFFIX = "MQTT/DC"; private static final String TOPIC_APPS_SUFFIX = "MQTT/APPS"; private static final String TOPIC_CONTROL_PREFIX = "topic.control-prefix"; private static final String TOPIC_CONTROL_PREFIX_DEFAULT = "$EDC"; private static final String TOPIC_WILD_CARD = "#"; private static final String DEVICE_DISPLAY_NAME = "device.display-name"; private static final String DEVICE_CUSTOM_NAME = "device.custom-name"; private static final String ENCODE_GZIP = "encode.gzip"; private static final String REPUB_BIRTH_ON_GPS_LOCK = "republish.mqtt.birth.cert.on.gps.lock"; private static final String REPUB_BIRTH_ON_TAMPER_EVENT = "republish.mqtt.birth.cert.on.tamper.event"; private static final String ENABLE_DFLT_SUBSCRIPTIONS = "enable.default.subscriptions"; private static final String PAYLOAD_ENCODING = "payload.encoding"; private static final int LIFECYCLE_PRIORITY = 0; private static final boolean LIFECYCLE_RETAIN = false; private final Map properties; private final SystemService systemService; public CloudServiceOptions(Map properties, SystemService systemService) { this.properties = properties; this.systemService = systemService; } /** * Returns the display name for the device. * * @return a String value. */ public String getDeviceDisplayName() { String displayName = ""; if (this.properties == null) { return displayName; } String deviceDisplayNameOption = (String) this.properties.get(DEVICE_DISPLAY_NAME); // Use the device name from SystemService. This should be kura.device.name from // the properties file. if ("device-name".equals(deviceDisplayNameOption)) { displayName = this.systemService.getDeviceName(); } // Try to get the device hostname else if ("hostname".equals(deviceDisplayNameOption)) { displayName = this.systemService.getHostname(); } // Return the custom field defined by the user else if ("custom".equals(deviceDisplayNameOption) && this.properties.get(DEVICE_CUSTOM_NAME) instanceof String) { displayName = (String) this.properties.get(DEVICE_CUSTOM_NAME); } // Return empty string to the server else if ("server".equals(deviceDisplayNameOption)) { displayName = ""; } return displayName; } /** * Returns true if the current CloudService configuration * specifies Gzip compression enabled for outgoing payloads. * * @return a boolean value. */ public boolean getEncodeGzip() { boolean encodeGzip = false; if (this.properties != null && this.properties.get(ENCODE_GZIP) instanceof Boolean) { encodeGzip = (Boolean) this.properties.get(ENCODE_GZIP); } return encodeGzip; } /** * Returns true if the current CloudService configuration * specifies the cloud client should republish the MQTT birth * certificate on GPS lock events. * * @return a boolean value. */ public boolean getRepubBirthCertOnGpsLock() { boolean repubBirth = false; if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_GPS_LOCK) instanceof Boolean) { repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_GPS_LOCK); } return repubBirth; } public boolean getRepubBirthCertOnTamperEvent() { boolean repubBirth = true; if (this.properties != null && this.properties.get(REPUB_BIRTH_ON_TAMPER_EVENT) instanceof Boolean) { repubBirth = (Boolean) this.properties.get(REPUB_BIRTH_ON_TAMPER_EVENT); } return repubBirth; } /** * Returns the prefix to be used when publishing messages to control topics. * * @return a String value. */ public String getTopicControlPrefix() { String prefix = TOPIC_CONTROL_PREFIX_DEFAULT; if (this.properties != null && this.properties.get(TOPIC_CONTROL_PREFIX) instanceof String) { prefix = (String) this.properties.get(TOPIC_CONTROL_PREFIX); } return prefix; } /** * Returns true if the current CloudService configuration * specifies that the cloud client should perform default subscriptions. * * @return a boolean value. */ public boolean getEnableDefaultSubscriptions() { boolean enable = true; if (this.properties != null && this.properties.get(ENABLE_DFLT_SUBSCRIPTIONS) instanceof Boolean) { enable = (Boolean) this.properties.get(ENABLE_DFLT_SUBSCRIPTIONS); } return enable; } /** * This method parses the Cloud Service configuration and returns the selected cloud payload encoding. * By default, this method returns {@link CloudPayloadEncoding} {@code KURA_PROTOBUF}. * * @return a boolean value. */ public CloudPayloadEncoding getPayloadEncoding() { CloudPayloadEncoding result = CloudPayloadEncoding.KURA_PROTOBUF; String encodingString = ""; if (this.properties != null && this.properties.get(PAYLOAD_ENCODING) != null && this.properties.get(PAYLOAD_ENCODING) instanceof String) { encodingString = (String) this.properties.get(PAYLOAD_ENCODING); } try { result = CloudPayloadEncoding.getEncoding(encodingString); } catch (IllegalArgumentException e) { logger.warn("Cannot parse the provided payload encoding.", e); } return result; } public static String getTopicSeparator() { return TOPIC_SEPARATOR; } public static String getTopicAccountToken() { return TOPIC_ACCOUNT_TOKEN; } public static String getTopicClientIdToken() { return TOPIC_CLIENT_ID_TOKEN; } public static String getTopicBirthSuffix() { return TOPIC_BIRTH_SUFFIX; } public static String getTopicDisconnectSuffix() { return TOPIC_DISCONNECT_SUFFIX; } public static String getTopicAppsSuffix() { return TOPIC_APPS_SUFFIX; } public static String getTopicWildCard() { return TOPIC_WILD_CARD; } public static int getLifeCycleMessagePriority() { return LIFECYCLE_PRIORITY; } public static boolean getLifeCycleMessageRetain() { return LIFECYCLE_RETAIN; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/KuraTopicImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import org.eclipse.kura.cloud.CloudService; import org.eclipse.kura.message.KuraApplicationTopic; /** * Models a topic for messages posted to the Kura platform. * Topics are expected to be in the form of "account/asset/<application_specific>"; * The system control topic prefix is defined in the {@link CloudService} and defaults * to $EDC. * */ public class KuraTopicImpl extends KuraApplicationTopic { private String fullTopic; private String[] topicParts; private String prefix; private String accountName; private String deviceId; public KuraTopicImpl(String fullTopic) { this(fullTopic, "$"); } public KuraTopicImpl(String fullTopic, String controlPrefix) { this.fullTopic = fullTopic; if (fullTopic.compareTo("#") == 0) { return; } this.topicParts = fullTopic.split("/"); if (this.topicParts.length == 0) { return; } // prefix int index = 0; int offset = 0; // skip a slash if (this.topicParts[0].startsWith(controlPrefix)) { this.prefix = this.topicParts[index]; offset += this.prefix.length() + 1; index++; } // account name if (index < this.topicParts.length) { this.accountName = this.topicParts[index]; offset += this.accountName.length() + 1; index++; } // deviceId if (index < this.topicParts.length) { this.deviceId = this.topicParts[index]; offset += this.deviceId.length() + 1; index++; } // applicationId if (index < this.topicParts.length) { this.applicationId = this.topicParts[index]; offset += this.applicationId.length() + 1; index++; } // applicationTopic if (offset < this.fullTopic.length()) { this.applicationTopic = this.fullTopic.substring(offset); } } public String getFullTopic() { return this.fullTopic; } public String[] getTopicParts() { return this.topicParts; } public String getPrefix() { return this.prefix; } public String getAccountName() { return this.accountName; } public String getDeviceId() { return this.deviceId; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/LifeCyclePayloadBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import java.util.List; import java.util.Map.Entry; import java.util.Optional; import org.eclipse.kura.core.util.NetUtil; import org.eclipse.kura.message.KuraBirthPayload; import org.eclipse.kura.message.KuraBirthPayload.KuraBirthPayloadBuilder; import org.eclipse.kura.message.KuraBirthPayload.TamperStatus; import org.eclipse.kura.message.KuraDeviceProfile; import org.eclipse.kura.message.KuraDisconnectPayload; import org.eclipse.kura.message.KuraPosition; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetworkService; import org.eclipse.kura.position.PositionService; import org.eclipse.kura.security.tamper.detection.TamperDetectionService; import org.eclipse.kura.system.ExtendedProperties; import org.eclipse.kura.system.ExtendedPropertyGroup; import org.eclipse.kura.system.SystemAdminService; import org.eclipse.kura.system.SystemService; import org.osgi.util.position.Position; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.eclipsesource.json.JsonObject; /** * Utility class to build lifecycle payload messages. */ public class LifeCyclePayloadBuilder { private static final String EXTENDED_PROPERTIES_KEY = "extended_properties"; private static final String ERROR = "ERROR"; private static final Logger logger = LoggerFactory.getLogger(LifeCyclePayloadBuilder.class); private static final String UNKNOWN = "UNKNOWN"; private final CloudServiceImpl cloudServiceImpl; LifeCyclePayloadBuilder(CloudServiceImpl cloudServiceImpl) { this.cloudServiceImpl = cloudServiceImpl; } public KuraBirthPayload buildBirthPayload() { // build device profile KuraDeviceProfile deviceProfile = buildDeviceProfile(); // build application IDs String appIds = buildApplicationIDs(); // build accept encoding String acceptEncoding = buildAcceptEncoding(); // build device name CloudServiceOptions cso = this.cloudServiceImpl.getCloudServiceOptions(); String deviceName = cso.getDeviceDisplayName(); if (deviceName == null) { deviceName = this.cloudServiceImpl.getSystemService().getDeviceName(); } String payloadEncoding = this.cloudServiceImpl.getCloudServiceOptions().getPayloadEncoding().name(); // build birth certificate KuraBirthPayloadBuilder birthPayloadBuilder = new KuraBirthPayloadBuilder(); birthPayloadBuilder.withUptime(deviceProfile.getUptime()).withDisplayName(deviceName) .withModelName(deviceProfile.getModelName()).withModelId(deviceProfile.getModelId()) .withPartNumber(deviceProfile.getPartNumber()).withSerialNumber(deviceProfile.getSerialNumber()) .withFirmwareVersion(deviceProfile.getFirmwareVersion()).withBiosVersion(deviceProfile.getBiosVersion()) .withCpuVersion(deviceProfile.getCpuVersion()).withOs(deviceProfile.getOs()) .withOsVersion(deviceProfile.getOsVersion()).withJvmName(deviceProfile.getJvmName()) .withJvmVersion(deviceProfile.getJvmVersion()).withJvmProfile(deviceProfile.getJvmProfile()) .withKuraVersion(deviceProfile.getApplicationFrameworkVersion()) .withConnectionInterface(deviceProfile.getConnectionInterface()) .withConnectionIp(deviceProfile.getConnectionIp()).withAcceptEncoding(acceptEncoding) .withApplicationIdentifiers(appIds).withAvailableProcessors(deviceProfile.getAvailableProcessors()) .withTotalMemory(deviceProfile.getTotalMemory()).withOsArch(deviceProfile.getOsArch()) .withOsgiFramework(deviceProfile.getOsgiFramework()) .withOsgiFrameworkVersion(deviceProfile.getOsgiFrameworkVersion()).withPayloadEncoding(payloadEncoding) .withJvmVendor(deviceProfile.getJvmVendor()).withJdkVendorVersion(deviceProfile.getJdkVendorVersion()); tryAddTamperStatus(birthPayloadBuilder); if (this.cloudServiceImpl.imei != null && this.cloudServiceImpl.imei.length() > 0 && !this.cloudServiceImpl.imei.equals(ERROR)) { birthPayloadBuilder.withModemImei(this.cloudServiceImpl.imei); } if (this.cloudServiceImpl.iccid != null && this.cloudServiceImpl.iccid.length() > 0 && !this.cloudServiceImpl.iccid.equals(ERROR)) { birthPayloadBuilder.withModemIccid(this.cloudServiceImpl.iccid); } if (this.cloudServiceImpl.imsi != null && this.cloudServiceImpl.imsi.length() > 0 && !this.cloudServiceImpl.imsi.equals(ERROR)) { birthPayloadBuilder.withModemImsi(this.cloudServiceImpl.imsi); } if (this.cloudServiceImpl.rssi != null && this.cloudServiceImpl.rssi.length() > 0) { birthPayloadBuilder.withModemRssi(this.cloudServiceImpl.rssi); } if (this.cloudServiceImpl.modemFwVer != null && this.cloudServiceImpl.modemFwVer.length() > 0 && !this.cloudServiceImpl.modemFwVer.equals(ERROR)) { birthPayloadBuilder.withModemFirmwareVersion(this.cloudServiceImpl.modemFwVer); } if (deviceProfile.getLatitude() != null && deviceProfile.getLongitude() != null) { KuraPosition kuraPosition = new KuraPosition(); kuraPosition.setLatitude(deviceProfile.getLatitude()); kuraPosition.setLongitude(deviceProfile.getLongitude()); kuraPosition.setAltitude(deviceProfile.getAltitude()); birthPayloadBuilder.withPosition(kuraPosition); } final KuraBirthPayload result = birthPayloadBuilder.build(); try { final Optional extendedProperties = serializeExtendedProperties(); if (extendedProperties.isPresent()) { result.addMetric(EXTENDED_PROPERTIES_KEY, extendedProperties.get()); } } catch (final Exception e) { logger.warn("failed to get extended properties", e); } return result; } private void tryAddTamperStatus(KuraBirthPayloadBuilder birthPayloadBuilder) { this.cloudServiceImpl.withTamperDetectionServices(t -> { if (t.isEmpty()) { return; } boolean isDeviceTampered = false; for (final TamperDetectionService tamperDetectionService : t) { if (isDeviceTampered) { break; } try { isDeviceTampered = tamperDetectionService.getTamperStatus().isDeviceTampered(); } catch (final Exception e) { logger.warn("failed to obtain tamper status", e); } } birthPayloadBuilder.withTamperStatus(isDeviceTampered ? TamperStatus.TAMPERED : TamperStatus.NOT_TAMPERED); }); } public KuraDisconnectPayload buildDisconnectPayload() { SystemService systemService = this.cloudServiceImpl.getSystemService(); SystemAdminService sysAdminService = this.cloudServiceImpl.getSystemAdminService(); CloudServiceOptions cloudOptions = this.cloudServiceImpl.getCloudServiceOptions(); // build device name String deviceName = cloudOptions.getDeviceDisplayName(); if (deviceName == null) { deviceName = systemService.getDeviceName(); } return new KuraDisconnectPayload(sysAdminService.getUptime(), deviceName); } public KuraDeviceProfile buildDeviceProfile() { SystemService systemService = this.cloudServiceImpl.getSystemService(); SystemAdminService sysAdminService = this.cloudServiceImpl.getSystemAdminService(); Optional networkService = this.cloudServiceImpl.getNetworkService(); Optional positionService = this.cloudServiceImpl.getPositionService(); // // get the network information if available StringBuilder sbConnectionIp = new StringBuilder(); StringBuilder sbConnectionInterface = new StringBuilder(); networkService.ifPresent(ns -> { try { List> nis = ns.getActiveNetworkInterfaces(); if (!nis.isEmpty()) { for (NetInterface ni : nis) { List nias = ni.getNetInterfaceAddresses(); if (nias != null && !nias.isEmpty()) { sbConnectionInterface.append(buildConnectionInterface(ni)).append(","); sbConnectionIp.append(buildConnectionIp(ni)).append(","); } } // Remove trailing comma sbConnectionIp.deleteCharAt(sbConnectionIp.length() - 1); sbConnectionInterface.deleteCharAt(sbConnectionInterface.length() - 1); } } catch (Exception se) { logger.warn("Error while getting ConnectionIP and ConnectionInterface", se); } }); String connectionIp = !sbConnectionIp.isEmpty() ? sbConnectionIp.toString() : UNKNOWN; String connectionInterface = !sbConnectionInterface.isEmpty() ? sbConnectionInterface.toString() : UNKNOWN; // // get the position information double latitude = 0.0; double longitude = 0.0; double altitude = 0.0; if (positionService.isPresent()) { Position position = positionService.get().getPosition(); if (position != null) { latitude = Math.toDegrees(position.getLatitude().getValue()); longitude = Math.toDegrees(position.getLongitude().getValue()); altitude = position.getAltitude().getValue(); } else { logger.warn("Unresolved PositionService reference."); } } return buildKuraDeviceProfile(systemService, sysAdminService, connectionIp, connectionInterface, latitude, longitude, altitude); } private KuraDeviceProfile buildKuraDeviceProfile(SystemService systemService, SystemAdminService sysAdminService, String connectionIp, String connectionInterface, double latitude, double longitude, double altitude) { KuraDeviceProfile kuraDeviceProfile = new KuraDeviceProfile(); kuraDeviceProfile.setUptime(sysAdminService.getUptime()); kuraDeviceProfile.setDisplayName(systemService.getDeviceName()); kuraDeviceProfile.setModelName(systemService.getModelName()); kuraDeviceProfile.setModelId(systemService.getModelId()); kuraDeviceProfile.setPartNumber(systemService.getPartNumber()); kuraDeviceProfile.setSerialNumber(systemService.getSerialNumber()); kuraDeviceProfile.setFirmwareVersion(systemService.getFirmwareVersion()); kuraDeviceProfile.setCpuVersion(systemService.getCpuVersion()); kuraDeviceProfile.setBiosVersion(systemService.getBiosVersion()); kuraDeviceProfile.setOs(systemService.getOsName()); kuraDeviceProfile.setOsVersion(systemService.getOsVersion()); kuraDeviceProfile.setJvmName(systemService.getJavaVmName()); kuraDeviceProfile.setJvmVersion(systemService.getJavaVmVersion() + " " + systemService.getJavaVmInfo()); kuraDeviceProfile.setJvmProfile(systemService.getJavaVendor() + " " + systemService.getJavaVersion()); kuraDeviceProfile.setApplicationFramework(KuraDeviceProfile.DEFAULT_APPLICATION_FRAMEWORK); kuraDeviceProfile.setApplicationFrameworkVersion(systemService.getKuraVersion()); kuraDeviceProfile.setConnectionInterface(connectionInterface); kuraDeviceProfile.setConnectionIp(connectionIp); kuraDeviceProfile.setLatitude(latitude); kuraDeviceProfile.setLongitude(longitude); kuraDeviceProfile.setAltitude(altitude); kuraDeviceProfile.setAvailableProcessors(String.valueOf(systemService.getNumberOfProcessors())); kuraDeviceProfile.setTotalMemory(String.valueOf(systemService.getTotalMemory())); kuraDeviceProfile.setOsArch(systemService.getOsArch()); kuraDeviceProfile.setOsgiFramework(systemService.getOsgiFwName()); kuraDeviceProfile.setOsgiFrameworkVersion(systemService.getOsgiFwVersion()); kuraDeviceProfile.setJvmVendor(systemService.getJavaVmVendor()); kuraDeviceProfile.setJdkVendorVersion(systemService.getJdkVendorVersion()); return kuraDeviceProfile; } private String buildConnectionIp(NetInterface ni) { String connectionIp = UNKNOWN; List nias = ni.getNetInterfaceAddresses(); if (nias != null && !nias.isEmpty() && nias.get(0).getAddress() != null) { connectionIp = nias.get(0).getAddress().getHostAddress(); } return connectionIp; } private String buildConnectionInterface(NetInterface ni) { StringBuilder sb = new StringBuilder(); sb.append(ni.getName()).append(" (").append(NetUtil.hardwareAddressToString(ni.getHardwareAddress())) .append(")"); return sb.toString(); } private String buildApplicationIDs() { String[] appIdArray = this.cloudServiceImpl.getCloudApplicationIdentifiers(); StringBuilder sbAppIDs = new StringBuilder(); for (int i = 0; i < appIdArray.length; i++) { if (i != 0) { sbAppIDs.append(","); } sbAppIDs.append(appIdArray[i]); } return sbAppIDs.toString(); } private String buildAcceptEncoding() { String acceptEncoding = ""; CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); if (options.getEncodeGzip()) { acceptEncoding = "gzip"; } return acceptEncoding; } private Optional serializeExtendedProperties() { final Optional extendedProperties = this.cloudServiceImpl.getSystemService() .getExtendedProperties(); if (!extendedProperties.isPresent()) { return Optional.empty(); } final JsonObject result = new JsonObject(); result.add("version", extendedProperties.get().getVersion()); final JsonObject jsonProperties = new JsonObject(); final List groups = extendedProperties.get().getPropertyGroups(); for (final ExtendedPropertyGroup group : groups) { final JsonObject properties = new JsonObject(); for (final Entry entry : group.getProperties().entrySet()) { final String value = entry.getValue(); if (value == null) { logger.warn("found null extended property: group {} property {}", group.getName(), entry.getKey()); continue; } properties.add(entry.getKey(), value); } jsonProperties.add(group.getName(), properties); } result.add("properties", jsonProperties); return Optional.of(result.toString()); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/LifecycleMessage.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import org.eclipse.kura.message.KuraPayload; public class LifecycleMessage { private StringBuilder topicBuilder; private LifeCyclePayloadBuilder payloadBuilder; private KuraPayload payload; private boolean isAppCertificateMessage = false; private boolean isBirthCertificateMessage = false; private int qos = 0; public LifecycleMessage(CloudServiceOptions options, CloudServiceImpl cloudServiceImpl) { this.topicBuilder = new StringBuilder(options.getTopicControlPrefix()); this.topicBuilder.append(CloudServiceOptions.getTopicSeparator()) .append(CloudServiceOptions.getTopicAccountToken()) .append(CloudServiceOptions.getTopicSeparator()) .append(CloudServiceOptions.getTopicClientIdToken()) .append(CloudServiceOptions.getTopicSeparator()); this.payloadBuilder = new LifeCyclePayloadBuilder(cloudServiceImpl); } public LifecycleMessage asBirthCertificateMessage() { this.topicBuilder.append(CloudServiceOptions.getTopicBirthSuffix()); this.payload = this.payloadBuilder.buildBirthPayload(); this.isBirthCertificateMessage = true; this.qos = 1; return this; } public LifecycleMessage asAppCertificateMessage() { this.topicBuilder.append(CloudServiceOptions.getTopicAppsSuffix()); this.payload = this.payloadBuilder.buildBirthPayload(); this.isAppCertificateMessage = true; this.qos = 1; return this; } public LifecycleMessage asDisconnectCertificateMessage() { this.topicBuilder.append(CloudServiceOptions.getTopicDisconnectSuffix()); this.payload = this.payloadBuilder.buildDisconnectPayload(); return this; } public String getTopic() { return this.topicBuilder.toString(); } public KuraPayload getPayload() { return this.payload; } public boolean isAppCertificateMessage() { return this.isAppCertificateMessage; } public boolean isBirthCertificateMessage() { return this.isBirthCertificateMessage; } public int getQos() { return this.qos; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/MessageHandlerCallable.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud; import static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.DEVICE_ID; import static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.NOTIFICATION_PUBLISHER_PID; import static org.eclipse.kura.cloudconnection.request.RequestHandlerContextConstants.TENANT_ID; import static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY; import java.io.PrintWriter; import java.io.StringWriter; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.audit.AuditConstants; import org.eclipse.kura.audit.AuditContext; import org.eclipse.kura.audit.AuditContext.Scope; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerContext; import org.eclipse.kura.data.DataService; import org.eclipse.kura.message.KuraPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MessageHandlerCallable implements Callable { private static final Logger auditLogger = LoggerFactory.getLogger("AuditLogger"); private static final Logger logger = LoggerFactory.getLogger(MessageHandlerCallable.class); private static final Pattern RESOURCES_DELIM = Pattern.compile("/"); public static final String METRIC_REQUEST_ID = "request.id"; public static final String REQUESTER_CLIENT_ID = "requester.client.id"; public static final String METRIC_RESPONSE_CODE = "response.code"; public static final String METRIC_EXCEPTION_MSG = "response.exception.message"; public static final String METRIC_EXCEPTION_STACK = "response.exception.stack"; public static final int RESPONSE_CODE_OK = 200; public static final int RESPONSE_CODE_BAD_REQUEST = 400; public static final int RESPONSE_CODE_NOTFOUND = 404; public static final int RESPONSE_CODE_ERROR = 500; protected static final int DFLT_PUB_QOS = 0; protected static final boolean DFLT_RETAIN = false; protected static final int DFLT_PRIORITY = 1; private final RequestHandler cloudApp; private final String appId; private final String appTopic; private final KuraPayload kuraMessage; private final CloudServiceImpl cloudService; private final RequestHandlerContext requestHandlerContext; public MessageHandlerCallable(RequestHandler cloudApp, String appId, String appTopic, KuraPayload msg, CloudServiceImpl cloudService) { super(); this.cloudApp = cloudApp; this.appId = appId; this.appTopic = appTopic; this.kuraMessage = msg; this.cloudService = cloudService; String notificationPublisherPid = this.cloudService.getNotificationPublisherPid(); CloudNotificationPublisher notificationPublisher = this.cloudService.getNotificationPublisher(); Map connectionProperties = this.cloudService.getInfo(); Map contextProperties = new HashMap<>(); contextProperties.put(NOTIFICATION_PUBLISHER_PID.name(), notificationPublisherPid); contextProperties.put(TENANT_ID.name(), connectionProperties.get("Account")); contextProperties.put(DEVICE_ID.name(), connectionProperties.get("Client ID")); this.requestHandlerContext = new RequestHandlerContext(notificationPublisher, contextProperties); } @Override public Void call() throws Exception { logger.debug("Control Arrived on topic: {}", this.appTopic); String requestId = (String) this.kuraMessage.getMetric(METRIC_REQUEST_ID); String requesterClientId = (String) this.kuraMessage.getMetric(REQUESTER_CLIENT_ID); if ( requestId == null || requesterClientId == null ) { if(logger.isDebugEnabled()) { logger.debug("Request Id or Requester Cliend Id is null"); } throw new ParseException("Not a valid request payload", 0); } // Prepare the default response KuraPayload reqPayload = this.kuraMessage; KuraMessage response; final Map auditProperties = new HashMap<>(); auditProperties.put(AuditConstants.KEY_ENTRY_POINT.getValue(), "DefaultCloudConnectionService"); auditProperties.put("cloud.app.id", this.appId); auditProperties.put("cloud.app.topic", this.appTopic); auditProperties.put("cloud.connection.pid", this.cloudService.getOwnPid()); try (final Scope scope = AuditContext.openScope(new AuditContext(auditProperties))) { try { Iterator resources = RESOURCES_DELIM.splitAsStream(this.appTopic).iterator(); if (!resources.hasNext()) { throw new IllegalArgumentException(); } String method = resources.next(); Map reqResources = getMessageResources(resources); KuraMessage reqMessage = new KuraMessage(reqPayload, reqResources); switch (method) { case "GET": logger.debug("Handling GET request topic: {}", this.appTopic); response = this.cloudApp.doGet(this.requestHandlerContext, reqMessage); break; case "PUT": logger.debug("Handling PUT request topic: {}", this.appTopic); response = this.cloudApp.doPut(this.requestHandlerContext, reqMessage); break; case "POST": logger.debug("Handling POST request topic: {}", this.appTopic); response = this.cloudApp.doPost(this.requestHandlerContext, reqMessage); break; case "DEL": logger.debug("Handling DEL request topic: {}", this.appTopic); response = this.cloudApp.doDel(this.requestHandlerContext, reqMessage); break; case "EXEC": logger.debug("Handling EXEC request topic: {}", this.appTopic); response = this.cloudApp.doExec(this.requestHandlerContext, reqMessage); break; default: logger.error("Bad request topic: {}", this.appTopic); KuraPayload payload = new KuraPayload(); response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); break; } } catch (IllegalArgumentException e) { logger.error("Bad request topic: {}", this.appTopic); KuraPayload payload = new KuraPayload(); response = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); } catch (KuraException e) { logger.error("Error handling request topic: {}", this.appTopic, e); response = manageException(e); } catch (Exception e) { logger.error("Unexpected failure handling response", e); KuraPayload payload = new KuraPayload(); response = setResponseCode(payload, RESPONSE_CODE_ERROR); } final Object responseCode = response.getPayload().getMetric(METRIC_RESPONSE_CODE); final boolean isSuccessful = responseCode instanceof Integer && (Integer) responseCode / 200 == 1; if (isSuccessful) { auditLogger.info("{} CloudCall - Success - Execute RequestHandler call", AuditContext.currentOrInternal()); } else { auditLogger.warn("{} CloudCall - Failure - Execute RequestHandler call", AuditContext.currentOrInternal()); } buildResponseMessage(requestId, requesterClientId, response); } return null; } private void buildResponseMessage(String requestId, String requesterClientId, KuraMessage response) { try { response.getPayload().setTimestamp(new Date()); StringBuilder sb = new StringBuilder("REPLY").append("/").append(requestId); logger.debug("Publishing response topic: {}", sb); DataService dataService = this.cloudService.getDataService(); String fullTopic = encodeTopic(requesterClientId, sb.toString()); byte[] appPayload = this.cloudService.encodePayload(response.getPayload()); dataService.publish(fullTopic, appPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY); } catch (KuraException e) { logger.error("Error publishing response for topic: {}\n{}", this.appTopic, e); } } private KuraMessage manageException(KuraException e) { KuraMessage message; KuraPayload payload = new KuraPayload(); setException(payload, e); if (e.getCode().equals(KuraErrorCode.BAD_REQUEST)) { message = setResponseCode(payload, RESPONSE_CODE_BAD_REQUEST); } else if (e.getCode().equals(KuraErrorCode.NOT_FOUND)) { message = setResponseCode(payload, RESPONSE_CODE_NOTFOUND); } else { message = setResponseCode(payload, RESPONSE_CODE_ERROR); } return message; } private Map getMessageResources(Iterator iter) { List resourcesList = new ArrayList<>(); while (iter.hasNext()) { resourcesList.add(iter.next()); } Map properties = new HashMap<>(); properties.put(ARGS_KEY.value(), resourcesList); return properties; } public KuraMessage setResponseCode(KuraPayload payload, int responseCode) { payload.addMetric(METRIC_RESPONSE_CODE, Integer.valueOf(responseCode)); return new KuraMessage(payload); } public void setException(KuraPayload payload, Throwable t) { if (t != null) { payload.addMetric(METRIC_EXCEPTION_MSG, t.getMessage()); } } @SuppressWarnings("unused") private String stackTraceAsString(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } private String encodeTopic(String deviceId, String appTopic) { CloudServiceOptions options = this.cloudService.getCloudServiceOptions(); StringBuilder sb = new StringBuilder(); sb.append(options.getTopicControlPrefix()).append(CloudServiceOptions.getTopicSeparator()); sb.append(CloudServiceOptions.getTopicAccountToken()).append(CloudServiceOptions.getTopicSeparator()) .append(deviceId).append(CloudServiceOptions.getTopicSeparator()).append(this.appId); if (appTopic != null && !appTopic.isEmpty()) { sb.append(CloudServiceOptions.getTopicSeparator()).append(appTopic); } return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/call/CloudCallServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.call; import java.io.IOException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraInvalidMessageException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.KuraTimeoutException; import org.eclipse.kura.cloud.CloudCallService; import org.eclipse.kura.cloud.app.RequestIdGenerator; import org.eclipse.kura.core.cloud.CloudPayloadProtoBufDecoderImpl; import org.eclipse.kura.core.cloud.CloudPayloadProtoBufEncoderImpl; import org.eclipse.kura.core.cloud.KuraTopicImpl; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.message.KuraApplicationTopic; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraRequestPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudCallServiceImpl implements CloudCallService, DataServiceListener { private static final Logger s_logger = LoggerFactory.getLogger(CloudCallServiceImpl.class); private static RequestIdGenerator s_generator = RequestIdGenerator.getInstance(); private static final int DFLT_PUB_QOS = 0; private static final boolean DFLT_RETAIN = false; private static final int DFLT_PRIORITY = 1; private static final String ACCOUNT_NAME_VAR_NAME = "#account-name"; private static final String CLIENT_ID_VAR_NAME = "#client-id"; private DataService m_dataService; private Object m_lock; private String m_respTopic; private KuraResponsePayload m_resp; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setDataService(DataService dataService) { this.m_dataService = dataService; } public void unsetDataService(DataService dataService) { this.m_dataService = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { s_logger.info("Activating..."); this.m_lock = new Object(); this.m_dataService.addDataServiceListener(this); } protected void deactivate(ComponentContext componentContext) { s_logger.info("Deactivating..."); this.m_dataService.removeDataServiceListener(this); synchronized (this.m_lock) { this.m_lock.notifyAll(); } } @Override public synchronized KuraResponsePayload call(String appId, String appTopic, KuraPayload appPayload, int timeout) throws KuraException { return call(CLIENT_ID_VAR_NAME, appId, appTopic, appPayload, timeout); } @Override public synchronized KuraResponsePayload call(String deviceId, String appId, String appTopic, KuraPayload appPayload, int timeout) throws KuraException { // Generate the request ID String requestId = s_generator.next(); StringBuilder sbReqTopic = new StringBuilder("$EDC").append("/").append(ACCOUNT_NAME_VAR_NAME).append("/") .append(deviceId).append("/").append(appId).append("/").append(appTopic); StringBuilder sbRespTopic = new StringBuilder("$EDC").append("/").append(ACCOUNT_NAME_VAR_NAME).append("/") .append(CLIENT_ID_VAR_NAME).append("/").append(appId).append("/").append("REPLY").append("/") .append(requestId); KuraRequestPayload req = null; if (appPayload != null) { // Construct a request payload req = new KuraRequestPayload(appPayload); } else { req = new KuraRequestPayload(); } req.setRequestId(requestId); req.setRequesterClientId(CLIENT_ID_VAR_NAME); CloudPayloadProtoBufEncoderImpl encoder = new CloudPayloadProtoBufEncoderImpl(req); byte[] rawPayload; try { rawPayload = encoder.getBytes(); } catch (IOException e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e, "Cannot encode request"); } this.m_respTopic = sbRespTopic.toString(); this.m_resp = null; this.m_dataService.subscribe(this.m_respTopic, 0); synchronized (this.m_lock) { try { this.m_dataService.publish(sbReqTopic.toString(), rawPayload, DFLT_PUB_QOS, DFLT_RETAIN, DFLT_PRIORITY); this.m_lock.wait(timeout); } catch (KuraStoreException e) { throw e; } catch (InterruptedException e) { // Avoid re-throwing this exception which should not normally happen s_logger.warn("Interrupted while waiting for the response"); Thread.currentThread().interrupt(); } finally { try { this.m_dataService.unsubscribe(this.m_respTopic); } catch (KuraException e) { s_logger.error("Cannot unsubscribe"); } this.m_respTopic = null; } } if (this.m_resp == null) { throw new KuraTimeoutException("Timed out while waiting for the response"); } return this.m_resp; } public void cancel() { synchronized (this.m_lock) { notifyAll(); } } @Override public void onConnectionEstablished() { // Ignore } @Override public void onDisconnecting() { // Ignore } @Override public void onDisconnected() { // Ignore } @Override public void onConnectionLost(Throwable cause) { // Ignore } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { s_logger.debug("Message arrived on topic: '{}'", topic); if (this.m_respTopic != null) { // Filter on application ID and topic KuraApplicationTopic kuraTopic = new KuraTopicImpl(topic); KuraApplicationTopic kuraRespTopic = new KuraTopicImpl(this.m_respTopic); if (kuraTopic.getApplicationId().equals(kuraRespTopic.getApplicationId()) && kuraTopic.getApplicationTopic().equals(kuraRespTopic.getApplicationTopic())) { s_logger.debug("Got response"); CloudPayloadProtoBufDecoderImpl decoder = new CloudPayloadProtoBufDecoderImpl(payload); KuraResponsePayload resp = null; try { KuraPayload kuraPayload = decoder.buildFromByteArray(); resp = new KuraResponsePayload(kuraPayload); } catch (KuraInvalidMessageException e) { s_logger.error("Cannot decode protobuf", e); } catch (IOException e) { s_logger.error("Cannot decode protobuf", e); } synchronized (this.m_lock) { this.m_resp = resp; // Can be null this.m_lock.notifyAll(); } } } } @Override public void onMessagePublished(int messageId, String topic) { // Ignore } @Override public void onMessageConfirmed(int messageId, String topic) { // Ignore } @Override public boolean isConnected() { return this.m_dataService.isConnected(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherImpl.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.publisher; import static java.util.Objects.nonNull; import static org.eclipse.kura.core.message.MessageConstants.APP_ID; import static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC; import static org.eclipse.kura.core.message.MessageConstants.CONTROL; import static org.eclipse.kura.core.message.MessageConstants.PRIORITY; import static org.eclipse.kura.core.message.MessageConstants.QOS; import static org.eclipse.kura.core.message.MessageConstants.RETAIN; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.core.cloud.CloudPublisherDeliveryListener; import org.eclipse.kura.core.cloud.CloudServiceImpl; import org.eclipse.kura.core.message.MessageType; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudPublisherImpl implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudPublisherDeliveryListener { private final class CloudConnectionManagerTrackerCustomizer implements ServiceTrackerCustomizer { @Override public CloudConnectionManager addingService(final ServiceReference reference) { CloudConnectionManager tempCloudService = CloudPublisherImpl.this.bundleContext.getService(reference); if (tempCloudService instanceof CloudServiceImpl) { CloudPublisherImpl.this.cloudServiceImpl = (CloudServiceImpl) tempCloudService; CloudPublisherImpl.this.cloudServiceImpl.registerCloudConnectionListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudServiceImpl .registerCloudPublisherDeliveryListener(CloudPublisherImpl.this); return tempCloudService; } else { CloudPublisherImpl.this.bundleContext.ungetService(reference); } return null; } @Override public void removedService(final ServiceReference reference, final CloudConnectionManager service) { CloudPublisherImpl.this.cloudServiceImpl.unregisterCloudConnectionListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudServiceImpl.unregisterCloudPublisherDeliveryListener(CloudPublisherImpl.this); CloudPublisherImpl.this.cloudServiceImpl = null; } @Override public void modifiedService(ServiceReference reference, CloudConnectionManager service) { // Not needed } } private static final Logger logger = LoggerFactory.getLogger(CloudPublisherImpl.class); private static final String TOPIC_PATTERN_STRING = "\\$([^\\s/]+)"; private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING); private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private final Set cloudDeliveryListeners = new CopyOnWriteArraySet<>(); private ServiceTrackerCustomizer cloudConnectionManagerTrackerCustomizer; private ServiceTracker cloudConnectionManagerTracker; private CloudPublisherOptions cloudPublisherOptions; private CloudServiceImpl cloudServiceImpl; private BundleContext bundleContext; private final ExecutorService worker = Executors.newCachedThreadPool(); protected void activate(ComponentContext componentContext, Map properties) { logger.debug("Activating Cloud Publisher..."); this.bundleContext = componentContext.getBundleContext(); this.cloudPublisherOptions = new CloudPublisherOptions(properties); this.cloudConnectionManagerTrackerCustomizer = new CloudConnectionManagerTrackerCustomizer(); initCloudConnectionManagerTracking(); logger.debug("Activating Cloud Publisher... Done"); } public void updated(Map properties) { logger.debug("Updating Cloud Publisher..."); this.cloudPublisherOptions = new CloudPublisherOptions(properties); if (nonNull(this.cloudConnectionManagerTracker)) { this.cloudConnectionManagerTracker.close(); } initCloudConnectionManagerTracking(); logger.debug("Updating Cloud Publisher... Done"); } protected void deactivate(ComponentContext componentContext) { logger.debug("Deactivating Cloud Publisher..."); if (nonNull(this.cloudConnectionManagerTracker)) { this.cloudConnectionManagerTracker.close(); } this.worker.shutdown(); logger.debug("Deactivating Cloud Publisher... Done"); } @Override public String publish(KuraMessage message) throws KuraException { if (this.cloudServiceImpl == null) { logger.info("Null cloud service"); throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "The Cloud Service is null."); } if (message == null) { logger.warn("Received null message!"); throw new IllegalArgumentException(); } String appTopic = fillAppTopicPlaceholders(this.cloudPublisherOptions.getAppTopic(), message); int qos = this.cloudPublisherOptions.getQos(); boolean retain = this.cloudPublisherOptions.isRetain(); int priority = this.cloudPublisherOptions.getPriority(); boolean isControl = MessageType.CONTROL.equals(this.cloudPublisherOptions.getMessageType()); Map publishMessageProps = new HashMap<>(); publishMessageProps.put(APP_TOPIC.name(), appTopic); publishMessageProps.put(APP_ID.name(), this.cloudPublisherOptions.getAppId()); publishMessageProps.put(QOS.name(), qos); publishMessageProps.put(RETAIN.name(), retain); publishMessageProps.put(PRIORITY.name(), priority); publishMessageProps.put(CONTROL.name(), isControl); KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps); return this.cloudServiceImpl.publish(publishMessage); } private String fillAppTopicPlaceholders(String appTopic, KuraMessage message) { Matcher matcher = TOPIC_PATTERN.matcher(appTopic); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { Map properties = message.getProperties(); if (properties.containsKey(matcher.group(1))) { String replacement = matcher.group(0); Object value = properties.get(matcher.group(1)); if (replacement != null) { matcher.appendReplacement(buffer, value.toString()); } } } matcher.appendTail(buffer); return buffer.toString(); } private void initCloudConnectionManagerTracking() { String selectedCloudServicePid = this.cloudPublisherOptions.getCloudServicePid(); String filterString = String.format("(&(%s=%s)(kura.service.pid=%s))", Constants.OBJECTCLASS, CloudConnectionManager.class.getName(), selectedCloudServicePid); Filter filter = null; try { filter = this.bundleContext.createFilter(filterString); } catch (InvalidSyntaxException e) { logger.error("Filter setup exception ", e); } this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter, this.cloudConnectionManagerTrackerCustomizer); this.cloudConnectionManagerTracker.open(); } @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected)); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost)); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished)); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } @Override public void onMessageConfirmed(String messageId, String topic) { if (topic.contains(this.cloudPublisherOptions.getAppId())) { this.cloudDeliveryListeners.forEach(listener -> this.worker.execute(() -> listener.onMessageConfirmed(messageId))); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/CloudPublisherOptions.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.publisher; import java.util.Map; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.core.message.MessageType; public class CloudPublisherOptions { private static final Property PROPERTY_CLOUD_SERVICE_PID = new Property<>( CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), "org.eclipse.kura.cloud.CloudService"); private static final Property PROPERTY_APP_ID = new Property<>("appId", "W1"); private static final Property PROPERTY_APP_TOPIC = new Property<>("app.topic", "A1/$assetName"); private static final Property PROPERTY_QOS = new Property<>("qos", 0); private static final Property PROPERTY_RETAIN = new Property<>("retain", false); private static final Property PROPERTY_MESSAGE_TYPE = new Property<>("message.type", "data"); private static final Property PROPERTY_PRIORITY = new Property<>("priority", 7); private final String cloudServicePid; private final String appId; private final String appTopic; private final int qos; private final boolean retain; private final String messageType; private final int priority; public CloudPublisherOptions(final Map properties) { this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties); this.appId = PROPERTY_APP_ID.get(properties); this.appTopic = PROPERTY_APP_TOPIC.get(properties); this.qos = PROPERTY_QOS.get(properties); this.retain = PROPERTY_RETAIN.get(properties); this.messageType = PROPERTY_MESSAGE_TYPE.get(properties); this.priority = PROPERTY_PRIORITY.get(properties); } public String getCloudServicePid() { return this.cloudServicePid; } public String getAppId() { return this.appId; } public String getAppTopic() { return this.appTopic; } public int getQos() { return this.qos; } public boolean isRetain() { return this.retain; } public MessageType getMessageType() { return MessageType.fromValue(this.messageType); } public int getPriority() { return this.priority; } private static final class Property { private final String key; private final T defaultValue; public Property(final String key, final T defaultValue) { this.key = key; this.defaultValue = defaultValue; } @SuppressWarnings("unchecked") public T get(final Map properties) { final Object value = properties.get(this.key); if (this.defaultValue.getClass().isInstance(value)) { return (T) value; } return this.defaultValue; } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/publisher/NotificationPublisherImpl.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.publisher; import static java.util.Objects.isNull; import static org.eclipse.kura.core.message.MessageConstants.CONTROL; import static org.eclipse.kura.core.message.MessageConstants.PRIORITY; import static org.eclipse.kura.core.message.MessageConstants.QOS; import static org.eclipse.kura.core.message.MessageConstants.RETAIN; import static org.eclipse.kura.core.message.MessageConstants.FULL_TOPIC; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudNotificationPublisher; import org.eclipse.kura.core.cloud.CloudServiceImpl; import org.eclipse.kura.core.cloud.CloudServiceOptions; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NotificationPublisherImpl implements CloudNotificationPublisher { private static final Logger logger = LoggerFactory.getLogger(NotificationPublisherImpl.class); private static final String TOPIC_PATTERN_STRING = "\\$([^\\s/]+)"; private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING); private static final int DFLT_PUB_QOS = 0; private static final boolean DFLT_RETAIN = false; private static final int DFLT_PRIORITY = 1; private static final String MESSAGE_TYPE_KEY = "messageType"; private static final String REQUESTOR_CLIENT_ID_KEY = "requestorClientId"; private static final String APP_ID_KEY = "appId"; private final CloudServiceImpl cloudServiceImpl; public NotificationPublisherImpl(CloudServiceImpl cloudServiceImpl) { this.cloudServiceImpl = cloudServiceImpl; } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { // Not needed } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { // Not needed } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { // Not needed } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { // Not needed } @Override public String publish(KuraMessage message) throws KuraException { if (this.cloudServiceImpl == null) { logger.warn("Null cloud connection"); throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "The Cloud Service is null."); } if (message == null) { logger.warn("Received null message!"); throw new IllegalArgumentException(); } String fullTopic = encodeFullTopic(message); Map publishMessageProps = new HashMap<>(); publishMessageProps.put(FULL_TOPIC.name(), fullTopic); publishMessageProps.put(QOS.name(), DFLT_PUB_QOS); publishMessageProps.put(RETAIN.name(), DFLT_RETAIN); publishMessageProps.put(PRIORITY.name(), DFLT_PRIORITY); publishMessageProps.put(CONTROL.name(), true); KuraMessage publishMessage = new KuraMessage(message.getPayload(), publishMessageProps); return this.cloudServiceImpl.publish(publishMessage); } private String encodeFullTopic(KuraMessage message) { String appId = (String) message.getProperties().get(APP_ID_KEY); String messageType = (String) message.getProperties().get(MESSAGE_TYPE_KEY); String requestorClientId = (String) message.getProperties().get(REQUESTOR_CLIENT_ID_KEY); if (isNull(appId) || isNull(messageType) || isNull(requestorClientId)) { throw new IllegalArgumentException("Incomplete properties in received message."); } String fullTopic = encodeTopic(appId, messageType, requestorClientId); return fillAppTopicPlaceholders(fullTopic, message); } private String encodeTopic(String appId, String messageType, String requestorClientId) { CloudServiceOptions options = this.cloudServiceImpl.getCloudServiceOptions(); String deviceId = options.getTopicClientIdToken(); String topicSeparator = options.getTopicSeparator(); StringBuilder sb = new StringBuilder(); sb.append(options.getTopicControlPrefix()).append(topicSeparator); sb.append(options.getTopicAccountToken()).append(topicSeparator).append(requestorClientId) .append(topicSeparator).append(appId); sb.append(topicSeparator).append("NOTIFY").append(topicSeparator).append(deviceId).append(topicSeparator) .append(messageType); return sb.toString(); } private String fillAppTopicPlaceholders(String fullTopic, KuraMessage message) { Matcher matcher = TOPIC_PATTERN.matcher(fullTopic); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { Map properties = message.getProperties(); if (properties.containsKey(matcher.group(1))) { String replacement = matcher.group(0); Object value = properties.get(matcher.group(1)); if (replacement != null) { matcher.appendReplacement(buffer, value.toString()); } } } matcher.appendTail(buffer); return buffer.toString(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriberImpl.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.subscriber; import static java.util.Objects.nonNull; import static org.eclipse.kura.core.message.MessageConstants.APP_ID; import static org.eclipse.kura.core.message.MessageConstants.APP_TOPIC; import static org.eclipse.kura.core.message.MessageConstants.CONTROL; import static org.eclipse.kura.core.message.MessageConstants.QOS; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.core.cloud.CloudServiceImpl; import org.eclipse.kura.core.message.MessageType; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudSubscriberImpl implements CloudSubscriber, ConfigurableComponent, CloudConnectionListener, CloudSubscriberListener { private final class CloudServiceTrackerCustomizer implements ServiceTrackerCustomizer { @Override public CloudConnectionManager addingService(final ServiceReference reference) { CloudConnectionManager tempCloudService = CloudSubscriberImpl.this.bundleContext.getService(reference); if (tempCloudService instanceof CloudServiceImpl) { CloudSubscriberImpl.this.cloudService = (CloudServiceImpl) tempCloudService; Map subscriptionProps = new HashMap<>(); subscriptionProps.put(APP_ID.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getAppId()); subscriptionProps.put(APP_TOPIC.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getAppTopic()); subscriptionProps.put(QOS.name(), CloudSubscriberImpl.this.cloudSubscriberOptions.getQos()); subscriptionProps.put(CONTROL.name(), MessageType.CONTROL.equals(CloudSubscriberImpl.this.cloudSubscriberOptions.getMessageType())); CloudSubscriberImpl.this.cloudService.registerSubscriber(subscriptionProps, CloudSubscriberImpl.this); CloudSubscriberImpl.this.cloudService.registerCloudConnectionListener(CloudSubscriberImpl.this); return tempCloudService; } else { CloudSubscriberImpl.this.bundleContext.ungetService(reference); } return null; } @Override public void removedService(final ServiceReference reference, final CloudConnectionManager service) { CloudSubscriberImpl.this.cloudService.unregisterSubscriber(CloudSubscriberImpl.this); CloudSubscriberImpl.this.cloudService.unregisterCloudConnectionListener(CloudSubscriberImpl.this); CloudSubscriberImpl.this.cloudService = null; } @Override public void modifiedService(ServiceReference reference, CloudConnectionManager service) { // Not needed } } private static final Logger logger = LoggerFactory.getLogger(CloudSubscriberImpl.class); private ServiceTrackerCustomizer cloudServiceTrackerCustomizer; private ServiceTracker cloudServiceTracker; private CloudSubscriberOptions cloudSubscriberOptions; private CloudServiceImpl cloudService; private BundleContext bundleContext; private final Set subscribers = new CopyOnWriteArraySet<>(); private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); protected void activate(ComponentContext componentContext, Map properties) { logger.debug("Activating Cloud Publisher..."); this.bundleContext = componentContext.getBundleContext(); this.cloudServiceTrackerCustomizer = new CloudServiceTrackerCustomizer(); doUpdate(properties); logger.debug("Activating Cloud Publisher... Done"); } public void updated(Map properties) { logger.debug("Updating Cloud Publisher..."); doUpdate(properties); logger.debug("Updating Cloud Publisher... Done"); } protected void deactivate(ComponentContext componentContext) { logger.debug("Deactivating Cloud Publisher..."); if (nonNull(this.cloudServiceTracker)) { this.cloudServiceTracker.close(); } logger.debug("Deactivating Cloud Publisher... Done"); } private void doUpdate(Map properties) { this.cloudSubscriberOptions = new CloudSubscriberOptions(properties); if (nonNull(this.cloudServiceTracker)) { this.cloudServiceTracker.close(); } initCloudServiceTracking(); } private void initCloudServiceTracking() { String selectedCloudServicePid = this.cloudSubscriberOptions.getCloudServicePid(); String filterString = String.format("(&(%s=%s)(kura.service.pid=%s))", Constants.OBJECTCLASS, CloudConnectionManager.class.getName(), selectedCloudServicePid); Filter filter = null; try { filter = this.bundleContext.createFilter(filterString); } catch (InvalidSyntaxException e) { logger.error("Filter setup exception ", e); } this.cloudServiceTracker = new ServiceTracker<>(this.bundleContext, filter, this.cloudServiceTrackerCustomizer); this.cloudServiceTracker.open(); } @Override public void registerCloudSubscriberListener(CloudSubscriberListener listener) { this.subscribers.add(listener); } @Override public void unregisterCloudSubscriberListener(CloudSubscriberListener listener) { this.subscribers.remove(listener); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(CloudConnectionListener::onConnectionEstablished); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach(CloudConnectionListener::onConnectionLost); } @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(CloudConnectionListener::onDisconnected); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void onMessageArrived(KuraMessage message) { this.subscribers.forEach(subscriber -> subscriber.onMessageArrived(message)); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriberOptions.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.subscriber; import java.util.Map; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.core.message.MessageType; public class CloudSubscriberOptions { private static final Property PROPERTY_CLOUD_SERVICE_PID = new Property<>( CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), "org.eclipse.kura.cloud.CloudService"); private static final Property PROPERTY_APP_ID = new Property<>("appId", "appId"); private static final Property PROPERTY_APP_TOPIC = new Property<>("app.topic", "#"); private static final Property PROPERTY_QOS = new Property<>("qos", 0); private static final Property PROPERTY_MESSAGE_TYPE = new Property<>("message.type", "data"); private final String cloudServicePid; private final String appId; private final String appTopic; private final int qos; private final String messageType; public CloudSubscriberOptions(final Map properties) { this.cloudServicePid = PROPERTY_CLOUD_SERVICE_PID.get(properties); this.appId = PROPERTY_APP_ID.get(properties); this.appTopic = PROPERTY_APP_TOPIC.get(properties); this.qos = PROPERTY_QOS.get(properties); this.messageType = PROPERTY_MESSAGE_TYPE.get(properties); } public String getCloudServicePid() { return this.cloudServicePid; } public String getAppId() { return this.appId; } public String getAppTopic() { return this.appTopic; } public int getQos() { return this.qos; } public MessageType getMessageType() { return MessageType.fromValue(this.messageType); } private static final class Property { private final String key; private final T defaultValue; public Property(final String key, final T defaultValue) { this.key = key; this.defaultValue = defaultValue; } @SuppressWarnings("unchecked") public T get(final Map properties) { final Object value = properties.get(this.key); if (this.defaultValue.getClass().isInstance(value)) { return (T) value; } return this.defaultValue; } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/cloud/subscriber/CloudSubscriptionRecord.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.cloud.subscriber; import org.eclipse.kura.core.cloud.CloudServiceOptions; import org.eclipse.kura.core.data.util.MqttTopicUtil; public class CloudSubscriptionRecord { private final String topic; private final int qos; private String topicFilter; public CloudSubscriptionRecord(final String topic, final int qos) { this.topic = topic; this.qos = qos; } public String getTopic() { return this.topic; } public int getQos() { return this.qos; } public boolean matches(final String topic) { if (topicFilter == null) { topicFilter = this.topic.replaceAll(CloudServiceOptions.getTopicAccountToken(), "+") .replaceAll(CloudServiceOptions.getTopicClientIdToken(), "+"); } return MqttTopicUtil.isMatched(this.topicFilter, topic); } @Override public int hashCode() { return topic.hashCode(); } @Override public boolean equals(final Object obj) { if (!(obj instanceof CloudSubscriptionRecord)) { return false; } return ((CloudSubscriptionRecord) obj).topic.equals(topic); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/MessageConstants.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.message; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber; /** * Internal enum providing constants for property sharing between {@link CloudPublisher}s or {@link CloudSubscriber}s * and {@link CloudConnectionManager} implementations. * * These constants are used as keys to identify the different properties shared in a {@link KuraMessage} to provide * context associated to a corresponding {@link KuraPayload} * */ public enum MessageConstants { FULL_TOPIC, APP_ID, APP_TOPIC, QOS, RETAIN, PRIORITY, CONTROL; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/MessageType.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.message; public enum MessageType { DATA("data"), CONTROL("control"); private String type; private MessageType(String type) { this.type = type; } public String value() { return this.type; } public static MessageType fromValue(String v) { for (MessageType mt : MessageType.values()) { if (mt.type.equals(v)) { return mt; } } throw new IllegalArgumentException(v); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/java/org/eclipse/kura/core/message/protobuf/KuraPayloadProto.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: kurapayload.proto // Protobuf Java Version: 4.29.3 package org.eclipse.kura.core.message.protobuf; public final class KuraPayloadProto { private KuraPayloadProto() {} static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPayloadProto.class.getName()); } public static void registerAllExtensions( com.google.protobuf.ExtensionRegistryLite registry) { } public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { registerAllExtensions( (com.google.protobuf.ExtensionRegistryLite) registry); } public interface KuraPayloadOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload) com.google.protobuf.GeneratedMessage. ExtendableMessageOrBuilder { /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ boolean hasTimestamp(); /** * optional int64 timestamp = 1; * @return The timestamp. */ long getTimestamp(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ boolean hasPosition(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition(); /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ java.util.List getMetricList(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ int getMetricCount(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ java.util.List getMetricOrBuilderList(); /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index); /** * optional bytes body = 5001; * @return Whether the body field is set. */ boolean hasBody(); /** * optional bytes body = 5001; * @return The body. */ com.google.protobuf.ByteString getBody(); } /** * Protobuf type {@code kuradatatypes.KuraPayload} */ public static final class KuraPayload extends com.google.protobuf.GeneratedMessage.ExtendableMessage< KuraPayload> implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload) KuraPayloadOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPayload.class.getName()); } // Use KuraPayload.newBuilder() to construct. private KuraPayload(com.google.protobuf.GeneratedMessage.ExtendableBuilder builder) { super(builder); } private KuraPayload() { metric_ = java.util.Collections.emptyList(); body_ = com.google.protobuf.ByteString.EMPTY; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class); } public interface KuraMetricOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraMetric) com.google.protobuf.MessageOrBuilder { /** * required string name = 1; * @return Whether the name field is set. */ boolean hasName(); /** * required string name = 1; * @return The name. */ java.lang.String getName(); /** * required string name = 1; * @return The bytes for name. */ com.google.protobuf.ByteString getNameBytes(); /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ boolean hasType(); /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType(); /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ boolean hasDoubleValue(); /** * optional double double_value = 3; * @return The doubleValue. */ double getDoubleValue(); /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ boolean hasFloatValue(); /** * optional float float_value = 4; * @return The floatValue. */ float getFloatValue(); /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ boolean hasLongValue(); /** * optional int64 long_value = 5; * @return The longValue. */ long getLongValue(); /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ boolean hasIntValue(); /** * optional int32 int_value = 6; * @return The intValue. */ int getIntValue(); /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ boolean hasBoolValue(); /** * optional bool bool_value = 7; * @return The boolValue. */ boolean getBoolValue(); /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ boolean hasStringValue(); /** * optional string string_value = 8; * @return The stringValue. */ java.lang.String getStringValue(); /** * optional string string_value = 8; * @return The bytes for stringValue. */ com.google.protobuf.ByteString getStringValueBytes(); /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ boolean hasBytesValue(); /** * optional bytes bytes_value = 9; * @return The bytesValue. */ com.google.protobuf.ByteString getBytesValue(); } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric} */ public static final class KuraMetric extends com.google.protobuf.GeneratedMessage implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraMetric) KuraMetricOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraMetric.class.getName()); } // Use KuraMetric.newBuilder() to construct. private KuraMetric(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } private KuraMetric() { name_ = ""; type_ = 0; stringValue_ = ""; bytesValue_ = com.google.protobuf.ByteString.EMPTY; } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class); } /** * Protobuf enum {@code kuradatatypes.KuraPayload.KuraMetric.ValueType} */ public enum ValueType implements com.google.protobuf.ProtocolMessageEnum { /** * DOUBLE = 0; */ DOUBLE(0), /** * FLOAT = 1; */ FLOAT(1), /** * INT64 = 2; */ INT64(2), /** * INT32 = 3; */ INT32(3), /** * BOOL = 4; */ BOOL(4), /** * STRING = 5; */ STRING(5), /** * BYTES = 6; */ BYTES(6), ; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", ValueType.class.getName()); } /** * DOUBLE = 0; */ public static final int DOUBLE_VALUE = 0; /** * FLOAT = 1; */ public static final int FLOAT_VALUE = 1; /** * INT64 = 2; */ public static final int INT64_VALUE = 2; /** * INT32 = 3; */ public static final int INT32_VALUE = 3; /** * BOOL = 4; */ public static final int BOOL_VALUE = 4; /** * STRING = 5; */ public static final int STRING_VALUE = 5; /** * BYTES = 6; */ public static final int BYTES_VALUE = 6; public final int getNumber() { return value; } /** * @param value The numeric wire value of the corresponding enum entry. * @return The enum associated with the given numeric wire value. * @deprecated Use {@link #forNumber(int)} instead. */ @java.lang.Deprecated public static ValueType valueOf(int value) { return forNumber(value); } /** * @param value The numeric wire value of the corresponding enum entry. * @return The enum associated with the given numeric wire value. */ public static ValueType forNumber(int value) { switch (value) { case 0: return DOUBLE; case 1: return FLOAT; case 2: return INT64; case 3: return INT32; case 4: return BOOL; case 5: return STRING; case 6: return BYTES; default: return null; } } public static com.google.protobuf.Internal.EnumLiteMap internalGetValueMap() { return internalValueMap; } private static final com.google.protobuf.Internal.EnumLiteMap< ValueType> internalValueMap = new com.google.protobuf.Internal.EnumLiteMap() { public ValueType findValueByNumber(int number) { return ValueType.forNumber(number); } }; public final com.google.protobuf.Descriptors.EnumValueDescriptor getValueDescriptor() { return getDescriptor().getValues().get(ordinal()); } public final com.google.protobuf.Descriptors.EnumDescriptor getDescriptorForType() { return getDescriptor(); } public static final com.google.protobuf.Descriptors.EnumDescriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDescriptor().getEnumTypes().get(0); } private static final ValueType[] VALUES = values(); public static ValueType valueOf( com.google.protobuf.Descriptors.EnumValueDescriptor desc) { if (desc.getType() != getDescriptor()) { throw new java.lang.IllegalArgumentException( "EnumValueDescriptor is not for this type."); } return VALUES[desc.getIndex()]; } private final int value; private ValueType(int value) { this.value = value; } // @@protoc_insertion_point(enum_scope:kuradatatypes.KuraPayload.KuraMetric.ValueType) } private int bitField0_; public static final int NAME_FIELD_NUMBER = 1; @SuppressWarnings("serial") private volatile java.lang.Object name_ = ""; /** * required string name = 1; * @return Whether the name field is set. */ @java.lang.Override public boolean hasName() { return ((bitField0_ & 0x00000001) != 0); } /** * required string name = 1; * @return The name. */ @java.lang.Override public java.lang.String getName() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { name_ = s; } return s; } } /** * required string name = 1; * @return The bytes for name. */ @java.lang.Override public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } public static final int TYPE_FIELD_NUMBER = 2; private int type_ = 0; /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ @java.lang.Override public boolean hasType() { return ((bitField0_ & 0x00000002) != 0); } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_); return result == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result; } public static final int DOUBLE_VALUE_FIELD_NUMBER = 3; private double doubleValue_ = 0D; /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ @java.lang.Override public boolean hasDoubleValue() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double double_value = 3; * @return The doubleValue. */ @java.lang.Override public double getDoubleValue() { return doubleValue_; } public static final int FLOAT_VALUE_FIELD_NUMBER = 4; private float floatValue_ = 0F; /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ @java.lang.Override public boolean hasFloatValue() { return ((bitField0_ & 0x00000008) != 0); } /** * optional float float_value = 4; * @return The floatValue. */ @java.lang.Override public float getFloatValue() { return floatValue_; } public static final int LONG_VALUE_FIELD_NUMBER = 5; private long longValue_ = 0L; /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ @java.lang.Override public boolean hasLongValue() { return ((bitField0_ & 0x00000010) != 0); } /** * optional int64 long_value = 5; * @return The longValue. */ @java.lang.Override public long getLongValue() { return longValue_; } public static final int INT_VALUE_FIELD_NUMBER = 6; private int intValue_ = 0; /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ @java.lang.Override public boolean hasIntValue() { return ((bitField0_ & 0x00000020) != 0); } /** * optional int32 int_value = 6; * @return The intValue. */ @java.lang.Override public int getIntValue() { return intValue_; } public static final int BOOL_VALUE_FIELD_NUMBER = 7; private boolean boolValue_ = false; /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ @java.lang.Override public boolean hasBoolValue() { return ((bitField0_ & 0x00000040) != 0); } /** * optional bool bool_value = 7; * @return The boolValue. */ @java.lang.Override public boolean getBoolValue() { return boolValue_; } public static final int STRING_VALUE_FIELD_NUMBER = 8; @SuppressWarnings("serial") private volatile java.lang.Object stringValue_ = ""; /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ @java.lang.Override public boolean hasStringValue() { return ((bitField0_ & 0x00000080) != 0); } /** * optional string string_value = 8; * @return The stringValue. */ @java.lang.Override public java.lang.String getStringValue() { java.lang.Object ref = stringValue_; if (ref instanceof java.lang.String) { return (java.lang.String) ref; } else { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { stringValue_ = s; } return s; } } /** * optional string string_value = 8; * @return The bytes for stringValue. */ @java.lang.Override public com.google.protobuf.ByteString getStringValueBytes() { java.lang.Object ref = stringValue_; if (ref instanceof java.lang.String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); stringValue_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } public static final int BYTES_VALUE_FIELD_NUMBER = 9; private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ @java.lang.Override public boolean hasBytesValue() { return ((bitField0_ & 0x00000100) != 0); } /** * optional bytes bytes_value = 9; * @return The bytesValue. */ @java.lang.Override public com.google.protobuf.ByteString getBytesValue() { return bytesValue_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (!hasName()) { memoizedIsInitialized = 0; return false; } if (!hasType()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (((bitField0_ & 0x00000001) != 0)) { com.google.protobuf.GeneratedMessage.writeString(output, 1, name_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeEnum(2, type_); } if (((bitField0_ & 0x00000004) != 0)) { output.writeDouble(3, doubleValue_); } if (((bitField0_ & 0x00000008) != 0)) { output.writeFloat(4, floatValue_); } if (((bitField0_ & 0x00000010) != 0)) { output.writeInt64(5, longValue_); } if (((bitField0_ & 0x00000020) != 0)) { output.writeInt32(6, intValue_); } if (((bitField0_ & 0x00000040) != 0)) { output.writeBool(7, boolValue_); } if (((bitField0_ & 0x00000080) != 0)) { com.google.protobuf.GeneratedMessage.writeString(output, 8, stringValue_); } if (((bitField0_ & 0x00000100) != 0)) { output.writeBytes(9, bytesValue_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.GeneratedMessage.computeStringSize(1, name_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeEnumSize(2, type_); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(3, doubleValue_); } if (((bitField0_ & 0x00000008) != 0)) { size += com.google.protobuf.CodedOutputStream .computeFloatSize(4, floatValue_); } if (((bitField0_ & 0x00000010) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(5, longValue_); } if (((bitField0_ & 0x00000020) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(6, intValue_); } if (((bitField0_ & 0x00000040) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBoolSize(7, boolValue_); } if (((bitField0_ & 0x00000080) != 0)) { size += com.google.protobuf.GeneratedMessage.computeStringSize(8, stringValue_); } if (((bitField0_ & 0x00000100) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(9, bytesValue_); } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)) { return super.equals(obj); } org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) obj; if (hasName() != other.hasName()) return false; if (hasName()) { if (!getName() .equals(other.getName())) return false; } if (hasType() != other.hasType()) return false; if (hasType()) { if (type_ != other.type_) return false; } if (hasDoubleValue() != other.hasDoubleValue()) return false; if (hasDoubleValue()) { if (java.lang.Double.doubleToLongBits(getDoubleValue()) != java.lang.Double.doubleToLongBits( other.getDoubleValue())) return false; } if (hasFloatValue() != other.hasFloatValue()) return false; if (hasFloatValue()) { if (java.lang.Float.floatToIntBits(getFloatValue()) != java.lang.Float.floatToIntBits( other.getFloatValue())) return false; } if (hasLongValue() != other.hasLongValue()) return false; if (hasLongValue()) { if (getLongValue() != other.getLongValue()) return false; } if (hasIntValue() != other.hasIntValue()) return false; if (hasIntValue()) { if (getIntValue() != other.getIntValue()) return false; } if (hasBoolValue() != other.hasBoolValue()) return false; if (hasBoolValue()) { if (getBoolValue() != other.getBoolValue()) return false; } if (hasStringValue() != other.hasStringValue()) return false; if (hasStringValue()) { if (!getStringValue() .equals(other.getStringValue())) return false; } if (hasBytesValue() != other.hasBytesValue()) return false; if (hasBytesValue()) { if (!getBytesValue() .equals(other.getBytesValue())) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasName()) { hash = (37 * hash) + NAME_FIELD_NUMBER; hash = (53 * hash) + getName().hashCode(); } if (hasType()) { hash = (37 * hash) + TYPE_FIELD_NUMBER; hash = (53 * hash) + type_; } if (hasDoubleValue()) { hash = (37 * hash) + DOUBLE_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getDoubleValue())); } if (hasFloatValue()) { hash = (37 * hash) + FLOAT_VALUE_FIELD_NUMBER; hash = (53 * hash) + java.lang.Float.floatToIntBits( getFloatValue()); } if (hasLongValue()) { hash = (37 * hash) + LONG_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getLongValue()); } if (hasIntValue()) { hash = (37 * hash) + INT_VALUE_FIELD_NUMBER; hash = (53 * hash) + getIntValue(); } if (hasBoolValue()) { hash = (37 * hash) + BOOL_VALUE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashBoolean( getBoolValue()); } if (hasStringValue()) { hash = (37 * hash) + STRING_VALUE_FIELD_NUMBER; hash = (53 * hash) + getStringValue().hashCode(); } if (hasBytesValue()) { hash = (37 * hash) + BYTES_VALUE_FIELD_NUMBER; hash = (53 * hash) + getBytesValue().hashCode(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraMetric} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraMetric) org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder.class); } // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.newBuilder() private Builder() { } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; name_ = ""; type_ = 0; doubleValue_ = 0D; floatValue_ = 0F; longValue_ = 0L; intValue_ = 0; boolValue_ = false; stringValue_ = ""; bytesValue_ = com.google.protobuf.ByteString.EMPTY; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric build() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric buildPartial() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(this); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.name_ = name_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.type_ = type_; to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000004) != 0)) { result.doubleValue_ = doubleValue_; to_bitField0_ |= 0x00000004; } if (((from_bitField0_ & 0x00000008) != 0)) { result.floatValue_ = floatValue_; to_bitField0_ |= 0x00000008; } if (((from_bitField0_ & 0x00000010) != 0)) { result.longValue_ = longValue_; to_bitField0_ |= 0x00000010; } if (((from_bitField0_ & 0x00000020) != 0)) { result.intValue_ = intValue_; to_bitField0_ |= 0x00000020; } if (((from_bitField0_ & 0x00000040) != 0)) { result.boolValue_ = boolValue_; to_bitField0_ |= 0x00000040; } if (((from_bitField0_ & 0x00000080) != 0)) { result.stringValue_ = stringValue_; to_bitField0_ |= 0x00000080; } if (((from_bitField0_ & 0x00000100) != 0)) { result.bytesValue_ = bytesValue_; to_bitField0_ |= 0x00000100; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric) { return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric other) { if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()) return this; if (other.hasName()) { name_ = other.name_; bitField0_ |= 0x00000001; onChanged(); } if (other.hasType()) { setType(other.getType()); } if (other.hasDoubleValue()) { setDoubleValue(other.getDoubleValue()); } if (other.hasFloatValue()) { setFloatValue(other.getFloatValue()); } if (other.hasLongValue()) { setLongValue(other.getLongValue()); } if (other.hasIntValue()) { setIntValue(other.getIntValue()); } if (other.hasBoolValue()) { setBoolValue(other.getBoolValue()); } if (other.hasStringValue()) { stringValue_ = other.stringValue_; bitField0_ |= 0x00000080; onChanged(); } if (other.hasBytesValue()) { setBytesValue(other.getBytesValue()); } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (!hasName()) { return false; } if (!hasType()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 10: { name_ = input.readBytes(); bitField0_ |= 0x00000001; break; } // case 10 case 16: { int tmpRaw = input.readEnum(); org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType tmpValue = org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(tmpRaw); if (tmpValue == null) { mergeUnknownVarintField(2, tmpRaw); } else { type_ = tmpRaw; bitField0_ |= 0x00000002; } break; } // case 16 case 25: { doubleValue_ = input.readDouble(); bitField0_ |= 0x00000004; break; } // case 25 case 37: { floatValue_ = input.readFloat(); bitField0_ |= 0x00000008; break; } // case 37 case 40: { longValue_ = input.readInt64(); bitField0_ |= 0x00000010; break; } // case 40 case 48: { intValue_ = input.readInt32(); bitField0_ |= 0x00000020; break; } // case 48 case 56: { boolValue_ = input.readBool(); bitField0_ |= 0x00000040; break; } // case 56 case 66: { stringValue_ = input.readBytes(); bitField0_ |= 0x00000080; break; } // case 66 case 74: { bytesValue_ = input.readBytes(); bitField0_ |= 0x00000100; break; } // case 74 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private java.lang.Object name_ = ""; /** * required string name = 1; * @return Whether the name field is set. */ public boolean hasName() { return ((bitField0_ & 0x00000001) != 0); } /** * required string name = 1; * @return The name. */ public java.lang.String getName() { java.lang.Object ref = name_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { name_ = s; } return s; } else { return (java.lang.String) ref; } } /** * required string name = 1; * @return The bytes for name. */ public com.google.protobuf.ByteString getNameBytes() { java.lang.Object ref = name_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); name_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * required string name = 1; * @param value The name to set. * @return This builder for chaining. */ public Builder setName( java.lang.String value) { if (value == null) { throw new NullPointerException(); } name_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * required string name = 1; * @return This builder for chaining. */ public Builder clearName() { name_ = getDefaultInstance().getName(); bitField0_ = (bitField0_ & ~0x00000001); onChanged(); return this; } /** * required string name = 1; * @param value The bytes for name to set. * @return This builder for chaining. */ public Builder setNameBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } name_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } private int type_ = 0; /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return Whether the type field is set. */ @java.lang.Override public boolean hasType() { return ((bitField0_ & 0x00000002) != 0); } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return The type. */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType getType() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType result = org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.forNumber(type_); return result == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType.DOUBLE : result; } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @param value The type to set. * @return This builder for chaining. */ public Builder setType(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.ValueType value) { if (value == null) { throw new NullPointerException(); } bitField0_ |= 0x00000002; type_ = value.getNumber(); onChanged(); return this; } /** * required .kuradatatypes.KuraPayload.KuraMetric.ValueType type = 2; * @return This builder for chaining. */ public Builder clearType() { bitField0_ = (bitField0_ & ~0x00000002); type_ = 0; onChanged(); return this; } private double doubleValue_ ; /** * optional double double_value = 3; * @return Whether the doubleValue field is set. */ @java.lang.Override public boolean hasDoubleValue() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double double_value = 3; * @return The doubleValue. */ @java.lang.Override public double getDoubleValue() { return doubleValue_; } /** * optional double double_value = 3; * @param value The doubleValue to set. * @return This builder for chaining. */ public Builder setDoubleValue(double value) { doubleValue_ = value; bitField0_ |= 0x00000004; onChanged(); return this; } /** * optional double double_value = 3; * @return This builder for chaining. */ public Builder clearDoubleValue() { bitField0_ = (bitField0_ & ~0x00000004); doubleValue_ = 0D; onChanged(); return this; } private float floatValue_ ; /** * optional float float_value = 4; * @return Whether the floatValue field is set. */ @java.lang.Override public boolean hasFloatValue() { return ((bitField0_ & 0x00000008) != 0); } /** * optional float float_value = 4; * @return The floatValue. */ @java.lang.Override public float getFloatValue() { return floatValue_; } /** * optional float float_value = 4; * @param value The floatValue to set. * @return This builder for chaining. */ public Builder setFloatValue(float value) { floatValue_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** * optional float float_value = 4; * @return This builder for chaining. */ public Builder clearFloatValue() { bitField0_ = (bitField0_ & ~0x00000008); floatValue_ = 0F; onChanged(); return this; } private long longValue_ ; /** * optional int64 long_value = 5; * @return Whether the longValue field is set. */ @java.lang.Override public boolean hasLongValue() { return ((bitField0_ & 0x00000010) != 0); } /** * optional int64 long_value = 5; * @return The longValue. */ @java.lang.Override public long getLongValue() { return longValue_; } /** * optional int64 long_value = 5; * @param value The longValue to set. * @return This builder for chaining. */ public Builder setLongValue(long value) { longValue_ = value; bitField0_ |= 0x00000010; onChanged(); return this; } /** * optional int64 long_value = 5; * @return This builder for chaining. */ public Builder clearLongValue() { bitField0_ = (bitField0_ & ~0x00000010); longValue_ = 0L; onChanged(); return this; } private int intValue_ ; /** * optional int32 int_value = 6; * @return Whether the intValue field is set. */ @java.lang.Override public boolean hasIntValue() { return ((bitField0_ & 0x00000020) != 0); } /** * optional int32 int_value = 6; * @return The intValue. */ @java.lang.Override public int getIntValue() { return intValue_; } /** * optional int32 int_value = 6; * @param value The intValue to set. * @return This builder for chaining. */ public Builder setIntValue(int value) { intValue_ = value; bitField0_ |= 0x00000020; onChanged(); return this; } /** * optional int32 int_value = 6; * @return This builder for chaining. */ public Builder clearIntValue() { bitField0_ = (bitField0_ & ~0x00000020); intValue_ = 0; onChanged(); return this; } private boolean boolValue_ ; /** * optional bool bool_value = 7; * @return Whether the boolValue field is set. */ @java.lang.Override public boolean hasBoolValue() { return ((bitField0_ & 0x00000040) != 0); } /** * optional bool bool_value = 7; * @return The boolValue. */ @java.lang.Override public boolean getBoolValue() { return boolValue_; } /** * optional bool bool_value = 7; * @param value The boolValue to set. * @return This builder for chaining. */ public Builder setBoolValue(boolean value) { boolValue_ = value; bitField0_ |= 0x00000040; onChanged(); return this; } /** * optional bool bool_value = 7; * @return This builder for chaining. */ public Builder clearBoolValue() { bitField0_ = (bitField0_ & ~0x00000040); boolValue_ = false; onChanged(); return this; } private java.lang.Object stringValue_ = ""; /** * optional string string_value = 8; * @return Whether the stringValue field is set. */ public boolean hasStringValue() { return ((bitField0_ & 0x00000080) != 0); } /** * optional string string_value = 8; * @return The stringValue. */ public java.lang.String getStringValue() { java.lang.Object ref = stringValue_; if (!(ref instanceof java.lang.String)) { com.google.protobuf.ByteString bs = (com.google.protobuf.ByteString) ref; java.lang.String s = bs.toStringUtf8(); if (bs.isValidUtf8()) { stringValue_ = s; } return s; } else { return (java.lang.String) ref; } } /** * optional string string_value = 8; * @return The bytes for stringValue. */ public com.google.protobuf.ByteString getStringValueBytes() { java.lang.Object ref = stringValue_; if (ref instanceof String) { com.google.protobuf.ByteString b = com.google.protobuf.ByteString.copyFromUtf8( (java.lang.String) ref); stringValue_ = b; return b; } else { return (com.google.protobuf.ByteString) ref; } } /** * optional string string_value = 8; * @param value The stringValue to set. * @return This builder for chaining. */ public Builder setStringValue( java.lang.String value) { if (value == null) { throw new NullPointerException(); } stringValue_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } /** * optional string string_value = 8; * @return This builder for chaining. */ public Builder clearStringValue() { stringValue_ = getDefaultInstance().getStringValue(); bitField0_ = (bitField0_ & ~0x00000080); onChanged(); return this; } /** * optional string string_value = 8; * @param value The bytes for stringValue to set. * @return This builder for chaining. */ public Builder setStringValueBytes( com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } stringValue_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } private com.google.protobuf.ByteString bytesValue_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes bytes_value = 9; * @return Whether the bytesValue field is set. */ @java.lang.Override public boolean hasBytesValue() { return ((bitField0_ & 0x00000100) != 0); } /** * optional bytes bytes_value = 9; * @return The bytesValue. */ @java.lang.Override public com.google.protobuf.ByteString getBytesValue() { return bytesValue_; } /** * optional bytes bytes_value = 9; * @param value The bytesValue to set. * @return This builder for chaining. */ public Builder setBytesValue(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } bytesValue_ = value; bitField0_ |= 0x00000100; onChanged(); return this; } /** * optional bytes bytes_value = 9; * @return This builder for chaining. */ public Builder clearBytesValue() { bitField0_ = (bitField0_ & ~0x00000100); bytesValue_ = getDefaultInstance().getBytesValue(); onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraMetric) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraMetric) private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric(); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraMetric parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } public interface KuraPositionOrBuilder extends // @@protoc_insertion_point(interface_extends:kuradatatypes.KuraPayload.KuraPosition) com.google.protobuf.MessageOrBuilder { /** * required double latitude = 1; * @return Whether the latitude field is set. */ boolean hasLatitude(); /** * required double latitude = 1; * @return The latitude. */ double getLatitude(); /** * required double longitude = 2; * @return Whether the longitude field is set. */ boolean hasLongitude(); /** * required double longitude = 2; * @return The longitude. */ double getLongitude(); /** * optional double altitude = 3; * @return Whether the altitude field is set. */ boolean hasAltitude(); /** * optional double altitude = 3; * @return The altitude. */ double getAltitude(); /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return Whether the precision field is set. */ boolean hasPrecision(); /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return The precision. */ double getPrecision(); /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return Whether the heading field is set. */ boolean hasHeading(); /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return The heading. */ double getHeading(); /** *
       * meters per second
       * 
* * optional double speed = 6; * @return Whether the speed field is set. */ boolean hasSpeed(); /** *
       * meters per second
       * 
* * optional double speed = 6; * @return The speed. */ double getSpeed(); /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ boolean hasTimestamp(); /** * optional int64 timestamp = 7; * @return The timestamp. */ long getTimestamp(); /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ boolean hasSatellites(); /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return The satellites. */ int getSatellites(); /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return Whether the status field is set. */ boolean hasStatus(); /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return The status. */ int getStatus(); } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition} */ public static final class KuraPosition extends com.google.protobuf.GeneratedMessage implements // @@protoc_insertion_point(message_implements:kuradatatypes.KuraPayload.KuraPosition) KuraPositionOrBuilder { private static final long serialVersionUID = 0L; static { com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion( com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC, /* major= */ 4, /* minor= */ 29, /* patch= */ 3, /* suffix= */ "", KuraPosition.class.getName()); } // Use KuraPosition.newBuilder() to construct. private KuraPosition(com.google.protobuf.GeneratedMessage.Builder builder) { super(builder); } private KuraPosition() { } public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class); } private int bitField0_; public static final int LATITUDE_FIELD_NUMBER = 1; private double latitude_ = 0D; /** * required double latitude = 1; * @return Whether the latitude field is set. */ @java.lang.Override public boolean hasLatitude() { return ((bitField0_ & 0x00000001) != 0); } /** * required double latitude = 1; * @return The latitude. */ @java.lang.Override public double getLatitude() { return latitude_; } public static final int LONGITUDE_FIELD_NUMBER = 2; private double longitude_ = 0D; /** * required double longitude = 2; * @return Whether the longitude field is set. */ @java.lang.Override public boolean hasLongitude() { return ((bitField0_ & 0x00000002) != 0); } /** * required double longitude = 2; * @return The longitude. */ @java.lang.Override public double getLongitude() { return longitude_; } public static final int ALTITUDE_FIELD_NUMBER = 3; private double altitude_ = 0D; /** * optional double altitude = 3; * @return Whether the altitude field is set. */ @java.lang.Override public boolean hasAltitude() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double altitude = 3; * @return The altitude. */ @java.lang.Override public double getAltitude() { return altitude_; } public static final int PRECISION_FIELD_NUMBER = 4; private double precision_ = 0D; /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return Whether the precision field is set. */ @java.lang.Override public boolean hasPrecision() { return ((bitField0_ & 0x00000008) != 0); } /** *
       * dilution of precision of the current satellite fix. 
       * 
* * optional double precision = 4; * @return The precision. */ @java.lang.Override public double getPrecision() { return precision_; } public static final int HEADING_FIELD_NUMBER = 5; private double heading_ = 0D; /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return Whether the heading field is set. */ @java.lang.Override public boolean hasHeading() { return ((bitField0_ & 0x00000010) != 0); } /** *
       * heading in degrees
       * 
* * optional double heading = 5; * @return The heading. */ @java.lang.Override public double getHeading() { return heading_; } public static final int SPEED_FIELD_NUMBER = 6; private double speed_ = 0D; /** *
       * meters per second
       * 
* * optional double speed = 6; * @return Whether the speed field is set. */ @java.lang.Override public boolean hasSpeed() { return ((bitField0_ & 0x00000020) != 0); } /** *
       * meters per second
       * 
* * optional double speed = 6; * @return The speed. */ @java.lang.Override public double getSpeed() { return speed_; } public static final int TIMESTAMP_FIELD_NUMBER = 7; private long timestamp_ = 0L; /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000040) != 0); } /** * optional int64 timestamp = 7; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } public static final int SATELLITES_FIELD_NUMBER = 8; private int satellites_ = 0; /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ @java.lang.Override public boolean hasSatellites() { return ((bitField0_ & 0x00000080) != 0); } /** *
       * number satellites locked by the GPS device
       * 
* * optional int32 satellites = 8; * @return The satellites. */ @java.lang.Override public int getSatellites() { return satellites_; } public static final int STATUS_FIELD_NUMBER = 9; private int status_ = 0; /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return Whether the status field is set. */ @java.lang.Override public boolean hasStatus() { return ((bitField0_ & 0x00000100) != 0); } /** *
       * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
       * 
* * optional int32 status = 9; * @return The status. */ @java.lang.Override public int getStatus() { return status_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (!hasLatitude()) { memoizedIsInitialized = 0; return false; } if (!hasLongitude()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { if (((bitField0_ & 0x00000001) != 0)) { output.writeDouble(1, latitude_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeDouble(2, longitude_); } if (((bitField0_ & 0x00000004) != 0)) { output.writeDouble(3, altitude_); } if (((bitField0_ & 0x00000008) != 0)) { output.writeDouble(4, precision_); } if (((bitField0_ & 0x00000010) != 0)) { output.writeDouble(5, heading_); } if (((bitField0_ & 0x00000020) != 0)) { output.writeDouble(6, speed_); } if (((bitField0_ & 0x00000040) != 0)) { output.writeInt64(7, timestamp_); } if (((bitField0_ & 0x00000080) != 0)) { output.writeInt32(8, satellites_); } if (((bitField0_ & 0x00000100) != 0)) { output.writeInt32(9, status_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(1, latitude_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(2, longitude_); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(3, altitude_); } if (((bitField0_ & 0x00000008) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(4, precision_); } if (((bitField0_ & 0x00000010) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(5, heading_); } if (((bitField0_ & 0x00000020) != 0)) { size += com.google.protobuf.CodedOutputStream .computeDoubleSize(6, speed_); } if (((bitField0_ & 0x00000040) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(7, timestamp_); } if (((bitField0_ & 0x00000080) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(8, satellites_); } if (((bitField0_ & 0x00000100) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt32Size(9, status_); } size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)) { return super.equals(obj); } org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) obj; if (hasLatitude() != other.hasLatitude()) return false; if (hasLatitude()) { if (java.lang.Double.doubleToLongBits(getLatitude()) != java.lang.Double.doubleToLongBits( other.getLatitude())) return false; } if (hasLongitude() != other.hasLongitude()) return false; if (hasLongitude()) { if (java.lang.Double.doubleToLongBits(getLongitude()) != java.lang.Double.doubleToLongBits( other.getLongitude())) return false; } if (hasAltitude() != other.hasAltitude()) return false; if (hasAltitude()) { if (java.lang.Double.doubleToLongBits(getAltitude()) != java.lang.Double.doubleToLongBits( other.getAltitude())) return false; } if (hasPrecision() != other.hasPrecision()) return false; if (hasPrecision()) { if (java.lang.Double.doubleToLongBits(getPrecision()) != java.lang.Double.doubleToLongBits( other.getPrecision())) return false; } if (hasHeading() != other.hasHeading()) return false; if (hasHeading()) { if (java.lang.Double.doubleToLongBits(getHeading()) != java.lang.Double.doubleToLongBits( other.getHeading())) return false; } if (hasSpeed() != other.hasSpeed()) return false; if (hasSpeed()) { if (java.lang.Double.doubleToLongBits(getSpeed()) != java.lang.Double.doubleToLongBits( other.getSpeed())) return false; } if (hasTimestamp() != other.hasTimestamp()) return false; if (hasTimestamp()) { if (getTimestamp() != other.getTimestamp()) return false; } if (hasSatellites() != other.hasSatellites()) return false; if (hasSatellites()) { if (getSatellites() != other.getSatellites()) return false; } if (hasStatus() != other.hasStatus()) return false; if (hasStatus()) { if (getStatus() != other.getStatus()) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasLatitude()) { hash = (37 * hash) + LATITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getLatitude())); } if (hasLongitude()) { hash = (37 * hash) + LONGITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getLongitude())); } if (hasAltitude()) { hash = (37 * hash) + ALTITUDE_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getAltitude())); } if (hasPrecision()) { hash = (37 * hash) + PRECISION_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getPrecision())); } if (hasHeading()) { hash = (37 * hash) + HEADING_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getHeading())); } if (hasSpeed()) { hash = (37 * hash) + SPEED_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( java.lang.Double.doubleToLongBits(getSpeed())); } if (hasTimestamp()) { hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getTimestamp()); } if (hasSatellites()) { hash = (37 * hash) + SATELLITES_FIELD_NUMBER; hash = (53 * hash) + getSatellites(); } if (hasStatus()) { hash = (37 * hash) + STATUS_FIELD_NUMBER; hash = (53 * hash) + getStatus(); } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload.KuraPosition} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.Builder implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload.KuraPosition) org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder.class); } // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.newBuilder() private Builder() { } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; latitude_ = 0D; longitude_ = 0D; altitude_ = 0D; precision_ = 0D; heading_ = 0D; speed_ = 0D; timestamp_ = 0L; satellites_ = 0; status_ = 0; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition build() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition buildPartial() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(this); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.latitude_ = latitude_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.longitude_ = longitude_; to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000004) != 0)) { result.altitude_ = altitude_; to_bitField0_ |= 0x00000004; } if (((from_bitField0_ & 0x00000008) != 0)) { result.precision_ = precision_; to_bitField0_ |= 0x00000008; } if (((from_bitField0_ & 0x00000010) != 0)) { result.heading_ = heading_; to_bitField0_ |= 0x00000010; } if (((from_bitField0_ & 0x00000020) != 0)) { result.speed_ = speed_; to_bitField0_ |= 0x00000020; } if (((from_bitField0_ & 0x00000040) != 0)) { result.timestamp_ = timestamp_; to_bitField0_ |= 0x00000040; } if (((from_bitField0_ & 0x00000080) != 0)) { result.satellites_ = satellites_; to_bitField0_ |= 0x00000080; } if (((from_bitField0_ & 0x00000100) != 0)) { result.status_ = status_; to_bitField0_ |= 0x00000100; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition) { return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition other) { if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) return this; if (other.hasLatitude()) { setLatitude(other.getLatitude()); } if (other.hasLongitude()) { setLongitude(other.getLongitude()); } if (other.hasAltitude()) { setAltitude(other.getAltitude()); } if (other.hasPrecision()) { setPrecision(other.getPrecision()); } if (other.hasHeading()) { setHeading(other.getHeading()); } if (other.hasSpeed()) { setSpeed(other.getSpeed()); } if (other.hasTimestamp()) { setTimestamp(other.getTimestamp()); } if (other.hasSatellites()) { setSatellites(other.getSatellites()); } if (other.hasStatus()) { setStatus(other.getStatus()); } this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (!hasLatitude()) { return false; } if (!hasLongitude()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 9: { latitude_ = input.readDouble(); bitField0_ |= 0x00000001; break; } // case 9 case 17: { longitude_ = input.readDouble(); bitField0_ |= 0x00000002; break; } // case 17 case 25: { altitude_ = input.readDouble(); bitField0_ |= 0x00000004; break; } // case 25 case 33: { precision_ = input.readDouble(); bitField0_ |= 0x00000008; break; } // case 33 case 41: { heading_ = input.readDouble(); bitField0_ |= 0x00000010; break; } // case 41 case 49: { speed_ = input.readDouble(); bitField0_ |= 0x00000020; break; } // case 49 case 56: { timestamp_ = input.readInt64(); bitField0_ |= 0x00000040; break; } // case 56 case 64: { satellites_ = input.readInt32(); bitField0_ |= 0x00000080; break; } // case 64 case 72: { status_ = input.readInt32(); bitField0_ |= 0x00000100; break; } // case 72 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private double latitude_ ; /** * required double latitude = 1; * @return Whether the latitude field is set. */ @java.lang.Override public boolean hasLatitude() { return ((bitField0_ & 0x00000001) != 0); } /** * required double latitude = 1; * @return The latitude. */ @java.lang.Override public double getLatitude() { return latitude_; } /** * required double latitude = 1; * @param value The latitude to set. * @return This builder for chaining. */ public Builder setLatitude(double value) { latitude_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * required double latitude = 1; * @return This builder for chaining. */ public Builder clearLatitude() { bitField0_ = (bitField0_ & ~0x00000001); latitude_ = 0D; onChanged(); return this; } private double longitude_ ; /** * required double longitude = 2; * @return Whether the longitude field is set. */ @java.lang.Override public boolean hasLongitude() { return ((bitField0_ & 0x00000002) != 0); } /** * required double longitude = 2; * @return The longitude. */ @java.lang.Override public double getLongitude() { return longitude_; } /** * required double longitude = 2; * @param value The longitude to set. * @return This builder for chaining. */ public Builder setLongitude(double value) { longitude_ = value; bitField0_ |= 0x00000002; onChanged(); return this; } /** * required double longitude = 2; * @return This builder for chaining. */ public Builder clearLongitude() { bitField0_ = (bitField0_ & ~0x00000002); longitude_ = 0D; onChanged(); return this; } private double altitude_ ; /** * optional double altitude = 3; * @return Whether the altitude field is set. */ @java.lang.Override public boolean hasAltitude() { return ((bitField0_ & 0x00000004) != 0); } /** * optional double altitude = 3; * @return The altitude. */ @java.lang.Override public double getAltitude() { return altitude_; } /** * optional double altitude = 3; * @param value The altitude to set. * @return This builder for chaining. */ public Builder setAltitude(double value) { altitude_ = value; bitField0_ |= 0x00000004; onChanged(); return this; } /** * optional double altitude = 3; * @return This builder for chaining. */ public Builder clearAltitude() { bitField0_ = (bitField0_ & ~0x00000004); altitude_ = 0D; onChanged(); return this; } private double precision_ ; /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return Whether the precision field is set. */ @java.lang.Override public boolean hasPrecision() { return ((bitField0_ & 0x00000008) != 0); } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return The precision. */ @java.lang.Override public double getPrecision() { return precision_; } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @param value The precision to set. * @return This builder for chaining. */ public Builder setPrecision(double value) { precision_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** *
         * dilution of precision of the current satellite fix. 
         * 
* * optional double precision = 4; * @return This builder for chaining. */ public Builder clearPrecision() { bitField0_ = (bitField0_ & ~0x00000008); precision_ = 0D; onChanged(); return this; } private double heading_ ; /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return Whether the heading field is set. */ @java.lang.Override public boolean hasHeading() { return ((bitField0_ & 0x00000010) != 0); } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return The heading. */ @java.lang.Override public double getHeading() { return heading_; } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @param value The heading to set. * @return This builder for chaining. */ public Builder setHeading(double value) { heading_ = value; bitField0_ |= 0x00000010; onChanged(); return this; } /** *
         * heading in degrees
         * 
* * optional double heading = 5; * @return This builder for chaining. */ public Builder clearHeading() { bitField0_ = (bitField0_ & ~0x00000010); heading_ = 0D; onChanged(); return this; } private double speed_ ; /** *
         * meters per second
         * 
* * optional double speed = 6; * @return Whether the speed field is set. */ @java.lang.Override public boolean hasSpeed() { return ((bitField0_ & 0x00000020) != 0); } /** *
         * meters per second
         * 
* * optional double speed = 6; * @return The speed. */ @java.lang.Override public double getSpeed() { return speed_; } /** *
         * meters per second
         * 
* * optional double speed = 6; * @param value The speed to set. * @return This builder for chaining. */ public Builder setSpeed(double value) { speed_ = value; bitField0_ |= 0x00000020; onChanged(); return this; } /** *
         * meters per second
         * 
* * optional double speed = 6; * @return This builder for chaining. */ public Builder clearSpeed() { bitField0_ = (bitField0_ & ~0x00000020); speed_ = 0D; onChanged(); return this; } private long timestamp_ ; /** * optional int64 timestamp = 7; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000040) != 0); } /** * optional int64 timestamp = 7; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } /** * optional int64 timestamp = 7; * @param value The timestamp to set. * @return This builder for chaining. */ public Builder setTimestamp(long value) { timestamp_ = value; bitField0_ |= 0x00000040; onChanged(); return this; } /** * optional int64 timestamp = 7; * @return This builder for chaining. */ public Builder clearTimestamp() { bitField0_ = (bitField0_ & ~0x00000040); timestamp_ = 0L; onChanged(); return this; } private int satellites_ ; /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return Whether the satellites field is set. */ @java.lang.Override public boolean hasSatellites() { return ((bitField0_ & 0x00000080) != 0); } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return The satellites. */ @java.lang.Override public int getSatellites() { return satellites_; } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @param value The satellites to set. * @return This builder for chaining. */ public Builder setSatellites(int value) { satellites_ = value; bitField0_ |= 0x00000080; onChanged(); return this; } /** *
         * number satellites locked by the GPS device
         * 
* * optional int32 satellites = 8; * @return This builder for chaining. */ public Builder clearSatellites() { bitField0_ = (bitField0_ & ~0x00000080); satellites_ = 0; onChanged(); return this; } private int status_ ; /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return Whether the status field is set. */ @java.lang.Override public boolean hasStatus() { return ((bitField0_ & 0x00000100) != 0); } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return The status. */ @java.lang.Override public int getStatus() { return status_; } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @param value The status to set. * @return This builder for chaining. */ public Builder setStatus(int value) { status_ = value; bitField0_ |= 0x00000100; onChanged(); return this; } /** *
         * status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid.
         * 
* * optional int32 status = 9; * @return This builder for chaining. */ public Builder clearStatus() { bitField0_ = (bitField0_ & ~0x00000100); status_ = 0; onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload.KuraPosition) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload.KuraPosition) private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition(); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraPosition parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private int bitField0_; public static final int TIMESTAMP_FIELD_NUMBER = 1; private long timestamp_ = 0L; /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000001) != 0); } /** * optional int64 timestamp = 1; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } public static final int POSITION_FIELD_NUMBER = 2; private org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_; /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ @java.lang.Override public boolean hasPosition() { return ((bitField0_ & 0x00000002) != 0); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() { return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() { return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } public static final int METRIC_FIELD_NUMBER = 5000; @SuppressWarnings("serial") private java.util.List metric_; /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public java.util.List getMetricList() { return metric_; } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public java.util.List getMetricOrBuilderList() { return metric_; } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public int getMetricCount() { return metric_.size(); } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) { return metric_.get(index); } /** *
     * can be zero, so optional
     * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index) { return metric_.get(index); } public static final int BODY_FIELD_NUMBER = 5001; private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes body = 5001; * @return Whether the body field is set. */ @java.lang.Override public boolean hasBody() { return ((bitField0_ & 0x00000004) != 0); } /** * optional bytes body = 5001; * @return The body. */ @java.lang.Override public com.google.protobuf.ByteString getBody() { return body_; } private byte memoizedIsInitialized = -1; @java.lang.Override public final boolean isInitialized() { byte isInitialized = memoizedIsInitialized; if (isInitialized == 1) return true; if (isInitialized == 0) return false; if (hasPosition()) { if (!getPosition().isInitialized()) { memoizedIsInitialized = 0; return false; } } for (int i = 0; i < getMetricCount(); i++) { if (!getMetric(i).isInitialized()) { memoizedIsInitialized = 0; return false; } } if (!extensionsAreInitialized()) { memoizedIsInitialized = 0; return false; } memoizedIsInitialized = 1; return true; } @java.lang.Override public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { com.google.protobuf.GeneratedMessage .ExtendableMessage.ExtensionSerializer extensionWriter = newExtensionSerializer(); if (((bitField0_ & 0x00000001) != 0)) { output.writeInt64(1, timestamp_); } if (((bitField0_ & 0x00000002) != 0)) { output.writeMessage(2, getPosition()); } extensionWriter.writeUntil(5000, output); for (int i = 0; i < metric_.size(); i++) { output.writeMessage(5000, metric_.get(i)); } if (((bitField0_ & 0x00000004) != 0)) { output.writeBytes(5001, body_); } getUnknownFields().writeTo(output); } @java.lang.Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) return size; size = 0; if (((bitField0_ & 0x00000001) != 0)) { size += com.google.protobuf.CodedOutputStream .computeInt64Size(1, timestamp_); } if (((bitField0_ & 0x00000002) != 0)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(2, getPosition()); } for (int i = 0; i < metric_.size(); i++) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(5000, metric_.get(i)); } if (((bitField0_ & 0x00000004) != 0)) { size += com.google.protobuf.CodedOutputStream .computeBytesSize(5001, body_); } size += extensionsSerializedSize(); size += getUnknownFields().getSerializedSize(); memoizedSize = size; return size; } @java.lang.Override public boolean equals(final java.lang.Object obj) { if (obj == this) { return true; } if (!(obj instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload)) { return super.equals(obj); } org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload other = (org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload) obj; if (hasTimestamp() != other.hasTimestamp()) return false; if (hasTimestamp()) { if (getTimestamp() != other.getTimestamp()) return false; } if (hasPosition() != other.hasPosition()) return false; if (hasPosition()) { if (!getPosition() .equals(other.getPosition())) return false; } if (!getMetricList() .equals(other.getMetricList())) return false; if (hasBody() != other.hasBody()) return false; if (hasBody()) { if (!getBody() .equals(other.getBody())) return false; } if (!getUnknownFields().equals(other.getUnknownFields())) return false; if (!getExtensionFields().equals(other.getExtensionFields())) return false; return true; } @java.lang.Override public int hashCode() { if (memoizedHashCode != 0) { return memoizedHashCode; } int hash = 41; hash = (19 * hash) + getDescriptor().hashCode(); if (hasTimestamp()) { hash = (37 * hash) + TIMESTAMP_FIELD_NUMBER; hash = (53 * hash) + com.google.protobuf.Internal.hashLong( getTimestamp()); } if (hasPosition()) { hash = (37 * hash) + POSITION_FIELD_NUMBER; hash = (53 * hash) + getPosition().hashCode(); } if (getMetricCount() > 0) { hash = (37 * hash) + METRIC_FIELD_NUMBER; hash = (53 * hash) + getMetricList().hashCode(); } if (hasBody()) { hash = (37 * hash) + BODY_FIELD_NUMBER; hash = (53 * hash) + getBody().hashCode(); } hash = hashFields(hash, getExtensionFields()); hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.nio.ByteBuffer data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.nio.ByteBuffer data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.ByteString data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.ByteString data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(byte[] data) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( byte[] data, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { return PARSER.parseFrom(data, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom(java.io.InputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseDelimitedFrom( java.io.InputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseDelimitedWithIOException(PARSER, input, extensionRegistry); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.CodedInputStream input) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload parseFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { return com.google.protobuf.GeneratedMessage .parseWithIOException(PARSER, input, extensionRegistry); } @java.lang.Override public Builder newBuilderForType() { return newBuilder(); } public static Builder newBuilder() { return DEFAULT_INSTANCE.toBuilder(); } public static Builder newBuilder(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload prototype) { return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); } @java.lang.Override public Builder toBuilder() { return this == DEFAULT_INSTANCE ? new Builder() : new Builder().mergeFrom(this); } @java.lang.Override protected Builder newBuilderForType( com.google.protobuf.GeneratedMessage.BuilderParent parent) { Builder builder = new Builder(parent); return builder; } /** * Protobuf type {@code kuradatatypes.KuraPayload} */ public static final class Builder extends com.google.protobuf.GeneratedMessage.ExtendableBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload, Builder> implements // @@protoc_insertion_point(builder_implements:kuradatatypes.KuraPayload) org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayloadOrBuilder { public static final com.google.protobuf.Descriptors.Descriptor getDescriptor() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override protected com.google.protobuf.GeneratedMessage.FieldAccessorTable internalGetFieldAccessorTable() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_fieldAccessorTable .ensureFieldAccessorsInitialized( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.class, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.Builder.class); } // Construct using org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.newBuilder() private Builder() { maybeForceBuilderInitialization(); } private Builder( com.google.protobuf.GeneratedMessage.BuilderParent parent) { super(parent); maybeForceBuilderInitialization(); } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage .alwaysUseFieldBuilders) { getPositionFieldBuilder(); getMetricFieldBuilder(); } } @java.lang.Override public Builder clear() { super.clear(); bitField0_ = 0; timestamp_ = 0L; position_ = null; if (positionBuilder_ != null) { positionBuilder_.dispose(); positionBuilder_ = null; } if (metricBuilder_ == null) { metric_ = java.util.Collections.emptyList(); } else { metric_ = null; metricBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000004); body_ = com.google.protobuf.ByteString.EMPTY; return this; } @java.lang.Override public com.google.protobuf.Descriptors.Descriptor getDescriptorForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.internal_static_kuradatatypes_KuraPayload_descriptor; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() { return org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance(); } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload build() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload buildPartial() { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload(this); buildPartialRepeatedFields(result); if (bitField0_ != 0) { buildPartial0(result); } onBuilt(); return result; } private void buildPartialRepeatedFields(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result) { if (metricBuilder_ == null) { if (((bitField0_ & 0x00000004) != 0)) { metric_ = java.util.Collections.unmodifiableList(metric_); bitField0_ = (bitField0_ & ~0x00000004); } result.metric_ = metric_; } else { result.metric_ = metricBuilder_.build(); } } private void buildPartial0(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload result) { int from_bitField0_ = bitField0_; int to_bitField0_ = 0; if (((from_bitField0_ & 0x00000001) != 0)) { result.timestamp_ = timestamp_; to_bitField0_ |= 0x00000001; } if (((from_bitField0_ & 0x00000002) != 0)) { result.position_ = positionBuilder_ == null ? position_ : positionBuilder_.build(); to_bitField0_ |= 0x00000002; } if (((from_bitField0_ & 0x00000008) != 0)) { result.body_ = body_; to_bitField0_ |= 0x00000004; } result.bitField0_ |= to_bitField0_; } @java.lang.Override public Builder mergeFrom(com.google.protobuf.Message other) { if (other instanceof org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload) { return mergeFrom((org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload)other); } else { super.mergeFrom(other); return this; } } public Builder mergeFrom(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload other) { if (other == org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.getDefaultInstance()) return this; if (other.hasTimestamp()) { setTimestamp(other.getTimestamp()); } if (other.hasPosition()) { mergePosition(other.getPosition()); } if (metricBuilder_ == null) { if (!other.metric_.isEmpty()) { if (metric_.isEmpty()) { metric_ = other.metric_; bitField0_ = (bitField0_ & ~0x00000004); } else { ensureMetricIsMutable(); metric_.addAll(other.metric_); } onChanged(); } } else { if (!other.metric_.isEmpty()) { if (metricBuilder_.isEmpty()) { metricBuilder_.dispose(); metricBuilder_ = null; metric_ = other.metric_; bitField0_ = (bitField0_ & ~0x00000004); metricBuilder_ = com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ? getMetricFieldBuilder() : null; } else { metricBuilder_.addAllMessages(other.metric_); } } } if (other.hasBody()) { setBody(other.getBody()); } this.mergeExtensionFields(other); this.mergeUnknownFields(other.getUnknownFields()); onChanged(); return this; } @java.lang.Override public final boolean isInitialized() { if (hasPosition()) { if (!getPosition().isInitialized()) { return false; } } for (int i = 0; i < getMetricCount(); i++) { if (!getMetric(i).isInitialized()) { return false; } } if (!extensionsAreInitialized()) { return false; } return true; } @java.lang.Override public Builder mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws java.io.IOException { if (extensionRegistry == null) { throw new java.lang.NullPointerException(); } try { boolean done = false; while (!done) { int tag = input.readTag(); switch (tag) { case 0: done = true; break; case 8: { timestamp_ = input.readInt64(); bitField0_ |= 0x00000001; break; } // case 8 case 18: { input.readMessage( getPositionFieldBuilder().getBuilder(), extensionRegistry); bitField0_ |= 0x00000002; break; } // case 18 case 40002: { org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric m = input.readMessage( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.parser(), extensionRegistry); if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(m); } else { metricBuilder_.addMessage(m); } break; } // case 40002 case 40010: { body_ = input.readBytes(); bitField0_ |= 0x00000008; break; } // case 40010 default: { if (!super.parseUnknownField(input, extensionRegistry, tag)) { done = true; // was an endgroup tag } break; } // default: } // switch (tag) } // while (!done) } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.unwrapIOException(); } finally { onChanged(); } // finally return this; } private int bitField0_; private long timestamp_ ; /** * optional int64 timestamp = 1; * @return Whether the timestamp field is set. */ @java.lang.Override public boolean hasTimestamp() { return ((bitField0_ & 0x00000001) != 0); } /** * optional int64 timestamp = 1; * @return The timestamp. */ @java.lang.Override public long getTimestamp() { return timestamp_; } /** * optional int64 timestamp = 1; * @param value The timestamp to set. * @return This builder for chaining. */ public Builder setTimestamp(long value) { timestamp_ = value; bitField0_ |= 0x00000001; onChanged(); return this; } /** * optional int64 timestamp = 1; * @return This builder for chaining. */ public Builder clearTimestamp() { bitField0_ = (bitField0_ & ~0x00000001); timestamp_ = 0L; onChanged(); return this; } private org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition position_; private com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> positionBuilder_; /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return Whether the position field is set. */ public boolean hasPosition() { return ((bitField0_ & 0x00000002) != 0); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; * @return The position. */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition getPosition() { if (positionBuilder_ == null) { return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } else { return positionBuilder_.getMessage(); } } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder setPosition(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) { if (positionBuilder_ == null) { if (value == null) { throw new NullPointerException(); } position_ = value; } else { positionBuilder_.setMessage(value); } bitField0_ |= 0x00000002; onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder setPosition( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder builderForValue) { if (positionBuilder_ == null) { position_ = builderForValue.build(); } else { positionBuilder_.setMessage(builderForValue.build()); } bitField0_ |= 0x00000002; onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder mergePosition(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition value) { if (positionBuilder_ == null) { if (((bitField0_ & 0x00000002) != 0) && position_ != null && position_ != org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance()) { getPositionBuilder().mergeFrom(value); } else { position_ = value; } } else { positionBuilder_.mergeFrom(value); } if (position_ != null) { bitField0_ |= 0x00000002; onChanged(); } return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public Builder clearPosition() { bitField0_ = (bitField0_ & ~0x00000002); position_ = null; if (positionBuilder_ != null) { positionBuilder_.dispose(); positionBuilder_ = null; } onChanged(); return this; } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder getPositionBuilder() { bitField0_ |= 0x00000002; onChanged(); return getPositionFieldBuilder().getBuilder(); } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder getPositionOrBuilder() { if (positionBuilder_ != null) { return positionBuilder_.getMessageOrBuilder(); } else { return position_ == null ? org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.getDefaultInstance() : position_; } } /** * optional .kuradatatypes.KuraPayload.KuraPosition position = 2; */ private com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder> getPositionFieldBuilder() { if (positionBuilder_ == null) { positionBuilder_ = new com.google.protobuf.SingleFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPosition.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraPositionOrBuilder>( getPosition(), getParentForChildren(), isClean()); position_ = null; } return positionBuilder_; } private java.util.List metric_ = java.util.Collections.emptyList(); private void ensureMetricIsMutable() { if (!((bitField0_ & 0x00000004) != 0)) { metric_ = new java.util.ArrayList(metric_); bitField0_ |= 0x00000004; } } private com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> metricBuilder_; /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricList() { if (metricBuilder_ == null) { return java.util.Collections.unmodifiableList(metric_); } else { return metricBuilder_.getMessageList(); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public int getMetricCount() { if (metricBuilder_ == null) { return metric_.size(); } else { return metricBuilder_.getCount(); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric getMetric(int index) { if (metricBuilder_ == null) { return metric_.get(index); } else { return metricBuilder_.getMessage(index); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder setMetric( int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.set(index, value); onChanged(); } else { metricBuilder_.setMessage(index, value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder setMetric( int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.set(index, builderForValue.build()); onChanged(); } else { metricBuilder_.setMessage(index, builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric(org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.add(value); onChanged(); } else { metricBuilder_.addMessage(value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric value) { if (metricBuilder_ == null) { if (value == null) { throw new NullPointerException(); } ensureMetricIsMutable(); metric_.add(index, value); onChanged(); } else { metricBuilder_.addMessage(index, value); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(builderForValue.build()); onChanged(); } else { metricBuilder_.addMessage(builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addMetric( int index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder builderForValue) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.add(index, builderForValue.build()); onChanged(); } else { metricBuilder_.addMessage(index, builderForValue.build()); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder addAllMetric( java.lang.Iterable values) { if (metricBuilder_ == null) { ensureMetricIsMutable(); com.google.protobuf.AbstractMessageLite.Builder.addAll( values, metric_); onChanged(); } else { metricBuilder_.addAllMessages(values); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder clearMetric() { if (metricBuilder_ == null) { metric_ = java.util.Collections.emptyList(); bitField0_ = (bitField0_ & ~0x00000004); onChanged(); } else { metricBuilder_.clear(); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public Builder removeMetric(int index) { if (metricBuilder_ == null) { ensureMetricIsMutable(); metric_.remove(index); onChanged(); } else { metricBuilder_.remove(index); } return this; } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder getMetricBuilder( int index) { return getMetricFieldBuilder().getBuilder(index); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder getMetricOrBuilder( int index) { if (metricBuilder_ == null) { return metric_.get(index); } else { return metricBuilder_.getMessageOrBuilder(index); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricOrBuilderList() { if (metricBuilder_ != null) { return metricBuilder_.getMessageOrBuilderList(); } else { return java.util.Collections.unmodifiableList(metric_); } } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder() { return getMetricFieldBuilder().addBuilder( org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder addMetricBuilder( int index) { return getMetricFieldBuilder().addBuilder( index, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.getDefaultInstance()); } /** *
       * can be zero, so optional
       * 
* * repeated .kuradatatypes.KuraPayload.KuraMetric metric = 5000; */ public java.util.List getMetricBuilderList() { return getMetricFieldBuilder().getBuilderList(); } private com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder> getMetricFieldBuilder() { if (metricBuilder_ == null) { metricBuilder_ = new com.google.protobuf.RepeatedFieldBuilder< org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetric.Builder, org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload.KuraMetricOrBuilder>( metric_, ((bitField0_ & 0x00000004) != 0), getParentForChildren(), isClean()); metric_ = null; } return metricBuilder_; } private com.google.protobuf.ByteString body_ = com.google.protobuf.ByteString.EMPTY; /** * optional bytes body = 5001; * @return Whether the body field is set. */ @java.lang.Override public boolean hasBody() { return ((bitField0_ & 0x00000008) != 0); } /** * optional bytes body = 5001; * @return The body. */ @java.lang.Override public com.google.protobuf.ByteString getBody() { return body_; } /** * optional bytes body = 5001; * @param value The body to set. * @return This builder for chaining. */ public Builder setBody(com.google.protobuf.ByteString value) { if (value == null) { throw new NullPointerException(); } body_ = value; bitField0_ |= 0x00000008; onChanged(); return this; } /** * optional bytes body = 5001; * @return This builder for chaining. */ public Builder clearBody() { bitField0_ = (bitField0_ & ~0x00000008); body_ = getDefaultInstance().getBody(); onChanged(); return this; } // @@protoc_insertion_point(builder_scope:kuradatatypes.KuraPayload) } // @@protoc_insertion_point(class_scope:kuradatatypes.KuraPayload) private static final org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload DEFAULT_INSTANCE; static { DEFAULT_INSTANCE = new org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload(); } public static org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstance() { return DEFAULT_INSTANCE; } private static final com.google.protobuf.Parser PARSER = new com.google.protobuf.AbstractParser() { @java.lang.Override public KuraPayload parsePartialFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) throws com.google.protobuf.InvalidProtocolBufferException { Builder builder = newBuilder(); try { builder.mergeFrom(input, extensionRegistry); } catch (com.google.protobuf.InvalidProtocolBufferException e) { throw e.setUnfinishedMessage(builder.buildPartial()); } catch (com.google.protobuf.UninitializedMessageException e) { throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial()); } catch (java.io.IOException e) { throw new com.google.protobuf.InvalidProtocolBufferException(e) .setUnfinishedMessage(builder.buildPartial()); } return builder.buildPartial(); } }; public static com.google.protobuf.Parser parser() { return PARSER; } @java.lang.Override public com.google.protobuf.Parser getParserForType() { return PARSER; } @java.lang.Override public org.eclipse.kura.core.message.protobuf.KuraPayloadProto.KuraPayload getDefaultInstanceForType() { return DEFAULT_INSTANCE; } } private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_fieldAccessorTable; private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable; private static final com.google.protobuf.Descriptors.Descriptor internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor; private static final com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable; public static com.google.protobuf.Descriptors.FileDescriptor getDescriptor() { return descriptor; } private static com.google.protobuf.Descriptors.FileDescriptor descriptor; static { java.lang.String[] descriptorData = { "\n\021kurapayload.proto\022\rkuradatatypes\"\243\005\n\013K" + "uraPayload\022\021\n\ttimestamp\030\001 \001(\003\0229\n\010positio" + "n\030\002 \001(\0132\'.kuradatatypes.KuraPayload.Kura" + "Position\0226\n\006metric\030\210\' \003(\0132%.kuradatatype" + "s.KuraPayload.KuraMetric\022\r\n\004body\030\211\' \001(\014\032" + "\305\002\n\nKuraMetric\022\014\n\004name\030\001 \002(\t\022=\n\004type\030\002 \002" + "(\0162/.kuradatatypes.KuraPayload.KuraMetri" + "c.ValueType\022\024\n\014double_value\030\003 \001(\001\022\023\n\013flo" + "at_value\030\004 \001(\002\022\022\n\nlong_value\030\005 \001(\003\022\021\n\tin" + "t_value\030\006 \001(\005\022\022\n\nbool_value\030\007 \001(\010\022\024\n\014str" + "ing_value\030\010 \001(\t\022\023\n\013bytes_value\030\t \001(\014\"Y\n\t" + "ValueType\022\n\n\006DOUBLE\020\000\022\t\n\005FLOAT\020\001\022\t\n\005INT6" + "4\020\002\022\t\n\005INT32\020\003\022\010\n\004BOOL\020\004\022\n\n\006STRING\020\005\022\t\n\005" + "BYTES\020\006\032\257\001\n\014KuraPosition\022\020\n\010latitude\030\001 \002" + "(\001\022\021\n\tlongitude\030\002 \002(\001\022\020\n\010altitude\030\003 \001(\001\022" + "\021\n\tprecision\030\004 \001(\001\022\017\n\007heading\030\005 \001(\001\022\r\n\005s" + "peed\030\006 \001(\001\022\021\n\ttimestamp\030\007 \001(\003\022\022\n\nsatelli" + "tes\030\010 \001(\005\022\016\n\006status\030\t \001(\005*\005\010\003\020\210\'B:\n&org." + "eclipse.kura.core.message.protobufB\020Kura" + "PayloadProto" }; descriptor = com.google.protobuf.Descriptors.FileDescriptor .internalBuildGeneratedFileFrom(descriptorData, new com.google.protobuf.Descriptors.FileDescriptor[] { }); internal_static_kuradatatypes_KuraPayload_descriptor = getDescriptor().getMessageTypes().get(0); internal_static_kuradatatypes_KuraPayload_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_descriptor, new java.lang.String[] { "Timestamp", "Position", "Metric", "Body", }); internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor = internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(0); internal_static_kuradatatypes_KuraPayload_KuraMetric_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_KuraMetric_descriptor, new java.lang.String[] { "Name", "Type", "DoubleValue", "FloatValue", "LongValue", "IntValue", "BoolValue", "StringValue", "BytesValue", }); internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor = internal_static_kuradatatypes_KuraPayload_descriptor.getNestedTypes().get(1); internal_static_kuradatatypes_KuraPayload_KuraPosition_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_kuradatatypes_KuraPayload_KuraPosition_descriptor, new java.lang.String[] { "Latitude", "Longitude", "Altitude", "Precision", "Heading", "Speed", "Timestamp", "Satellites", "Status", }); descriptor.resolveAllFeaturesImmutable(); } // @@protoc_insertion_point(outer_class_scope) } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.kapua.mqtt.provider/src/main/protobuf/kurapayload.proto ================================================ // // To compile: // protoc --proto_path=src/main/protobuf --java_out=src/main/java src/main/protobuf/kurapayload.proto // syntax = "proto2"; package kuradatatypes; option java_package = "org.eclipse.kura.core.message.protobuf"; option java_outer_classname = "KuraPayloadProto"; message KuraPayload { message KuraMetric { enum ValueType { DOUBLE = 0; FLOAT = 1; INT64 = 2; INT32 = 3; BOOL = 4; STRING = 5; BYTES = 6; } required string name = 1; required ValueType type = 2; optional double double_value = 3; optional float float_value = 4; optional int64 long_value = 5; optional int32 int_value = 6; optional bool bool_value = 7; optional string string_value = 8; optional bytes bytes_value = 9; } message KuraPosition { required double latitude = 1; required double longitude = 2; optional double altitude = 3; optional double precision = 4; // dilution of precision of the current satellite fix. optional double heading = 5; // heading in degrees optional double speed = 6; // meters per second optional int64 timestamp = 7; optional int32 satellites = 8; // number satellites locked by the GPS device optional int32 status = 9; // status indicator for the GPS data: 1 = no GPS response; 2 = error in response; 4 = valid. } optional int64 timestamp = 1; optional KuraPosition position = 2; extensions 3 to 4999; repeated KuraMetric metric = 5000; // can be zero, so optional optional bytes body = 5001; } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Raw MQTT Cloud Connection Provider Bundle-SymbolicName: org.eclipse.kura.cloudconnection.raw.mqtt.provider;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.cloud;version="[1.1,2.0)", org.eclipse.kura.cloudconnection;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.factory;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.listener;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber.listener;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.core.data.util;version="[1.0,2.0)", org.eclipse.kura.data;version="[1.0,2.0)", org.eclipse.kura.data.listener;version="[1.0,1.1)", org.eclipse.kura.message;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.1", org.osgi.util.tracker;version="1.5.1", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloud.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudServiceFactory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/cloudSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.publisher.RawMqttPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.RawMqttSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/build.properties ================================================ # # Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes bin.includes = .,\ META-INF/,\ about.html,\ OSGI-INF/,\ about_files/ src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.cloudconnection.raw.mqtt.provider 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/Constants.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.cloud; public final class Constants { public static final String TOPIC_PROP_NAME = "topic"; private Constants() { } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/Qos.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.cloud; public enum Qos { QOS0(0), QOS1(1), QOS2(2); private final int value; private Qos(final int value) { this.value = value; } public int getValue() { return this.value; } public static Qos valueOf(final int i) { if (i == 0) { return QOS0; } else if (i == 1) { return QOS1; } else if (i == 2) { return QOS2; } throw new IllegalArgumentException(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/cloud/RawMqttCloudEndpoint.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.cloud; import static org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils.catchAll; import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraDisconnectException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.cloud.CloudConnectionEstablishedEvent; import org.eclipse.kura.cloud.CloudConnectionLostEvent; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.raw.mqtt.publisher.PublishOptions; import org.eclipse.kura.cloudconnection.raw.mqtt.subscriber.SubscribeOptions; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.data.util.MqttTopicUtil; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.listener.DataServiceListener; import org.eclipse.kura.message.KuraPayload; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RawMqttCloudEndpoint implements CloudEndpoint, CloudConnectionManager, DataServiceListener, ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(RawMqttCloudEndpoint.class); private DataService dataService; private EventAdmin eventAdmin; private ComponentContext componentContext; private final Set cloudDeliveryListeners = new CopyOnWriteArraySet<>(); private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private final Map> subscribers = new ConcurrentHashMap<>(); public void setDataService(final DataService dataService) { this.dataService = dataService; } public void unsetDataService(final DataService dataService) { this.dataService = null; } public void setEventAdmin(final EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void unsetEventAdmin(final EventAdmin eventAdmin) { this.eventAdmin = null; } public void activated(final ComponentContext componentContext) { logger.info("activating..."); this.componentContext = componentContext; this.dataService.addDataServiceListener(this); if (this.dataService.isConnected()) { onConnectionEstablished(); } logger.info("activating...done"); } public void updated() { logger.info("updating..."); logger.info("updating...done"); } public void deactivated() { logger.info("deactivating..."); this.dataService.removeDataServiceListener(this); synchronized (this) { this.subscribers.keySet().forEach(this::unsubscribe); } logger.info("deactivating...done"); } @Override public void connect() throws KuraConnectException { this.dataService.connect(); } @Override public void disconnect() throws KuraDisconnectException { this.dataService.disconnect(10); } @Override public boolean isConnected() { return this.dataService.isConnected(); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public String publish(final KuraMessage message) throws KuraException { return publish(new PublishOptions(message.getProperties()), message.getPayload()); } public String publish(final PublishOptions options, final KuraPayload kuraPayload) throws KuraException { final byte[] body = kuraPayload.getBody(); if (body == null) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Missing message body in received payload."); } final int qos = options.getQos().getValue(); final int id = this.dataService.publish(options.getTopic(), body, qos, options.getRetain(), options.getPriority()); if (qos == 0) { return null; } else { return Integer.toString(id); } } @Override public synchronized void registerSubscriber(final Map subscriptionProperties, final CloudSubscriberListener cloudSubscriberListener) { final SubscribeOptions subscribeOptions; try { subscribeOptions = new SubscribeOptions(subscriptionProperties); } catch (final Exception e) { throw new IllegalArgumentException(e); } registerSubscriber(subscribeOptions, cloudSubscriberListener); } public synchronized void registerSubscriber(final SubscribeOptions subscribeOptions, final CloudSubscriberListener cloudSubscriberListener) { final Set listeners = this.subscribers.computeIfAbsent(subscribeOptions, e -> new CopyOnWriteArraySet<>()); listeners.add(cloudSubscriberListener); subscribe(subscribeOptions); } @Override public synchronized void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener) { final Set toUnsubscribe = new HashSet<>(); this.subscribers.entrySet().removeIf(e -> { final Set listeners = e.getValue(); listeners.remove(cloudSubscriberListener); if (listeners.isEmpty()) { toUnsubscribe.add(e.getKey()); return true; } else { return false; } }); toUnsubscribe.forEach(this::unsubscribe); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onConnectionEstablished)); synchronized (this) { this.subscribers.keySet().forEach(this::subscribe); } postConnectionStateChangeEvent(true); } @Override public void onDisconnecting() { // do nothing } @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onDisconnected)); postConnectionStateChangeEvent(false); } @Override public void onConnectionLost(Throwable cause) { this.cloudConnectionListeners.forEach(catchAll(CloudConnectionListener::onConnectionLost)); postConnectionStateChangeEvent(false); } @Override public void onMessageArrived(final String topic, final byte[] payload, final int qos, final boolean retained) { logger.info("message arrived on topic {}", topic); final KuraPayload kuraPayload = new KuraPayload(); kuraPayload.setBody(payload); final Map messagePropertes = Collections.singletonMap(Constants.TOPIC_PROP_NAME, topic); final KuraMessage message = new KuraMessage(kuraPayload, messagePropertes); for (final Entry> e : this.subscribers.entrySet()) { if (MqttTopicUtil.isMatched(e.getKey().getTopicFilter(), topic)) { e.getValue().forEach(catchAll(l -> l.onMessageArrived(message))); } } } @Override public void onMessagePublished(final int messageId, final String topic) { // do nothing } @Override public void onMessageConfirmed(int messageId, String topic) { this.cloudDeliveryListeners.forEach(catchAll(l -> l.onMessageConfirmed(Integer.toString(messageId)))); } private void postConnectionStateChangeEvent(final boolean isConnected) { final Map eventProperties = Collections.singletonMap("cloud.service.pid", (String) this.componentContext.getProperties().get(ConfigurationService.KURA_SERVICE_PID)); final Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties) : new CloudConnectionLostEvent(eventProperties); this.eventAdmin.postEvent(event); } private void subscribe(final SubscribeOptions options) { try { final String topicFilter = options.getTopicFilter(); final int qos = options.getQos().getValue(); logger.info("subscribing to {} with qos {}", topicFilter, qos); this.dataService.subscribe(topicFilter, qos); } catch (final KuraNotConnectedException e) { logger.debug("failed to subscribe, DataService not connected"); } catch (final Exception e) { logger.warn("failed to subscribe", e); } } private void unsubscribe(final SubscribeOptions options) { try { final String topicFilter = options.getTopicFilter(); logger.info("unsubscribing from {}", topicFilter); this.dataService.unsubscribe(topicFilter); } catch (final KuraNotConnectedException e) { logger.debug("failed to unsubscribe, DataService not connected"); } catch (final Exception e) { logger.warn("failed to unsubscribe", e); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/factory/RawMqttCloudConnectionFactory.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.factory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentConstants; public class RawMqttCloudConnectionFactory implements CloudConnectionFactory { private static final String FACTORY_PID = "org.eclipse.kura.cloudconnection.raw.mqtt.factory.RawMqttCloudConnectionFactory"; // The following constants must match the factory component definitions private static final String CLOUD_ENDPOINT_FACTORY_PID = "org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint"; private static final String DATA_SERVICE_FACTORY_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String CLOUD_SERVICE_PID = "org.eclipse.kura.cloudconnection.raw.mqtt.CloudEndpoint"; private static final String DATA_SERVICE_PID = "org.eclipse.kura.cloudconnection.raw.mqtt.DataService"; private static final String DATA_TRANSPORT_SERVICE_PID = "org.eclipse.kura.cloudconnection.raw.mqtt.MqttDataTransport"; private static final String DATA_SERVICE_REFERENCE_NAME = "DataService"; private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = "DataTransportService"; private static final String REFERENCE_TARGET_VALUE_FORMAT = "(" + ConfigurationService.KURA_SERVICE_PID + "=%s)"; private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern .compile("^org\\.eclipse\\.kura\\.cloudconnection\\.raw\\.mqtt\\.CloudEndpoint(-[a-zA-Z0-9]+)?$"); private ConfigurationService configurationService; protected void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } protected void unsetConfigurationService(ConfigurationService configurationService) { if (configurationService == this.configurationService) { this.configurationService = null; } } @Override public String getFactoryPid() { return CLOUD_ENDPOINT_FACTORY_PID; } @Override public void createConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } // create the CloudService layer and set the selective dependency on the DataService PID Map cloudServiceProperties = new HashMap<>(); String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid)); cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID); this.configurationService.createFactoryConfiguration(CLOUD_ENDPOINT_FACTORY_PID, pid, cloudServiceProperties, false); // create the DataService layer and set the selective dependency on the DataTransportService PID Map dataServiceProperties = new HashMap<>(); name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid)); this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid, dataServiceProperties, false); // create the DataTransportService layer and take a snapshot this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID, dataTransportServicePid, null, true); } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public void deleteConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } this.configurationService.deleteFactoryConfiguration(pid, false); this.configurationService.deleteFactoryConfiguration(dataServicePid, false); this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true); } } @Override public List getStackComponentsPids(String pid) throws KuraException { List componentPids = new ArrayList<>(); String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } componentPids.add(pid); componentPids.add(dataServicePid); componentPids.add(dataTransportServicePid); return componentPids; } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public Set getManagedCloudConnectionPids() throws KuraException { final BundleContext context = FrameworkUtil.getBundle(RawMqttCloudConnectionFactory.class).getBundleContext(); try { return context.getServiceReferences(CloudEndpoint.class, null).stream().filter(ref -> { final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID); if (!(kuraServicePid instanceof String)) { return false; } return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches() && FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID)); }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet()); } catch (InvalidSyntaxException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/publisher/PublishOptions.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.publisher; import java.util.Map; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.raw.mqtt.cloud.Qos; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.Property; public class PublishOptions { public static final Property TOPIC_PROP = new Property<>("topic", String.class); public static final Property QOS_PROP = new Property<>("qos", 0).map(Qos.class, Qos::valueOf); public static final Property RETAIN_PROP = new Property<>("retain", false); public static final Property PRIORITY_PROP = new Property<>("priority", 4); private final String topic; private final Qos qos; private final boolean retain; private final int priority; public PublishOptions(final Map properties) throws KuraException { this.topic = TOPIC_PROP.get(properties); this.qos = QOS_PROP.getOrDefault(properties); this.retain = RETAIN_PROP.getOrDefault(properties); this.priority = PRIORITY_PROP.getOrDefault(properties); } public String getTopic() { return this.topic; } public Qos getQos() { return this.qos; } public boolean getRetain() { return this.retain; } public int getPriority() { return this.priority; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/publisher/RawMqttPublisher.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.publisher; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.AbstractStackComponent; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RawMqttPublisher extends AbstractStackComponent implements CloudPublisher, CloudDeliveryListener { private static final Logger logger = LoggerFactory.getLogger(RawMqttPublisher.class); private final Set cloudDeliveryListeners = new CopyOnWriteArraySet<>(); @Override protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) { super.setCloudEndpoint(endpoint); endpoint.registerCloudDeliveryListener(this); } @Override protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) { endpoint.unregisterCloudConnectionListener(this); super.unsetCloudEndpoint(endpoint); } @Override public String publish(final KuraMessage message) throws KuraException { final StackComponentOptions currentOptions = getOptions(); final Optional publishOptions = currentOptions.getComponentOptions(); if (!publishOptions.isPresent()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, null, null, "invalid publish configuration"); } final Optional currentEndpoint = getEndpoint(); if (!currentEndpoint.isPresent()) { throw new KuraException(KuraErrorCode.NOT_FOUND, null, null, "cloud endpoint not bound"); } return currentEndpoint.get().publish(publishOptions.get(), message.getPayload()); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } @Override public void onMessageConfirmed(String messageId) { this.cloudDeliveryListeners.forEach(Utils.catchAll(l -> l.onMessageConfirmed(messageId))); } @Override protected Logger getLogger() { return logger; } @Override protected OptionsFactory getOptionsFactory() { return PublishOptions::new; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/subscriber/RawMqttSubscriber.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.subscriber; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint; import org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.AbstractStackComponent; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RawMqttSubscriber extends AbstractStackComponent implements CloudSubscriber, CloudSubscriberListener { private static final Logger logger = LoggerFactory.getLogger(RawMqttSubscriber.class); private final Set cloudSubscriberListeners = new CopyOnWriteArraySet<>(); @Override protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) { super.setCloudEndpoint(endpoint); trySubscribe(); } @Override protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) { tryUnsubscribe(); super.unsetCloudEndpoint(endpoint); } @Override public void registerCloudSubscriberListener(final CloudSubscriberListener listener) { this.cloudSubscriberListeners.add(listener); } @Override public void unregisterCloudSubscriberListener(final CloudSubscriberListener listener) { this.cloudSubscriberListeners.remove(listener); } @Override public void onMessageArrived(final KuraMessage message) { this.cloudSubscriberListeners.forEach(Utils.catchAll(l -> l.onMessageArrived(message))); } private void trySubscribe() { final Optional endpoint = getEndpoint(); if (!endpoint.isPresent()) { return; } final RawMqttCloudEndpoint currentEndpoint = endpoint.get(); currentEndpoint.unregisterSubscriber(this); final StackComponentOptions options = getOptions(); final Optional subscribeOptions = options.getComponentOptions(); if (subscribeOptions.isPresent()) { currentEndpoint.registerSubscriber(subscribeOptions.get(), this); } } private void tryUnsubscribe() { final Optional endpoint = getEndpoint(); if (endpoint.isPresent()) { endpoint.get().unregisterSubscriber(this); } } @Override protected Logger getLogger() { return logger; } @Override protected OptionsFactory getOptionsFactory() { return SubscribeOptions::new; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/raw/mqtt/subscriber/SubscribeOptions.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.raw.mqtt.subscriber; import java.util.Map; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.raw.mqtt.cloud.Qos; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.Property; import org.eclipse.kura.core.data.util.MqttTopicUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SubscribeOptions { private static final Logger logger = LoggerFactory.getLogger(SubscribeOptions.class); public static final Property TOPIC_FILTER_PROP = new Property<>("topic.filter", String.class) .validate(SubscribeOptions::validateTopicFilter); public static final Property QOS_PROP = new Property<>("qos", 0).map(Qos.class, Qos::valueOf); private final String topicFilter; private final Qos qos; public SubscribeOptions(final Map properties) throws KuraException { this.topicFilter = TOPIC_FILTER_PROP.get(properties); this.qos = QOS_PROP.get(properties); } public String getTopicFilter() { return this.topicFilter; } public Qos getQos() { return this.qos; } private static boolean validateTopicFilter(final String filter) { try { MqttTopicUtil.validate(filter, true); return true; } catch (final Exception e) { logger.warn("invalid topic filter", e); return false; } } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.qos == null ? 0 : this.qos.hashCode()); result = prime * result + (this.topicFilter == null ? 0 : this.topicFilter.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } SubscribeOptions other = (SubscribeOptions) obj; if (this.qos != other.qos) { return false; } if (this.topicFilter == null) { if (other.topicFilter != null) { return false; } } else if (!this.topicFilter.equals(other.topicFilter)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/AbstractStackComponent.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnecton.raw.mqtt.util; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.atomic.AtomicReference; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.raw.mqtt.cloud.RawMqttCloudEndpoint; import org.eclipse.kura.cloudconnecton.raw.mqtt.util.StackComponentOptions.OptionsFactory; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; public abstract class AbstractStackComponent implements ConfigurableComponent, CloudConnectionListener { private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private final AtomicReference> options = new AtomicReference<>(); private final AtomicReference> endpoint = new AtomicReference<>(Optional.empty()); private ServiceTracker tracker; private final BundleContext context = FrameworkUtil.getBundle(AbstractStackComponent.class).getBundleContext(); protected abstract Logger getLogger(); protected abstract OptionsFactory getOptionsFactory(); protected void setCloudEndpoint(final RawMqttCloudEndpoint endpoint) { this.endpoint.set(Optional.of(endpoint)); endpoint.registerCloudConnectionListener(this); } protected void unsetCloudEndpoint(final RawMqttCloudEndpoint endpoint) { endpoint.unregisterCloudConnectionListener(this); this.endpoint.set(Optional.empty()); } public void activated(final Map properties) { getLogger().info("activating..."); updated(properties); getLogger().info("activating...done"); } public void updated(final Map properties) { getLogger().info("updating..."); this.options.set(new StackComponentOptions<>(properties, getOptionsFactory())); reopenTracker(); getLogger().info("updating...done"); } public void deactivated() { getLogger().info("deactivating..."); shutdownTracker(); getLogger().info("deactivating...done"); } protected StackComponentOptions getOptions() { return this.options.get(); } protected Optional getEndpoint() { return this.endpoint.get(); } private void shutdownTracker() { if (this.tracker != null) { this.tracker.close(); this.tracker = null; } } private void reopenTracker() { shutdownTracker(); final StackComponentOptions currentOptions = this.options.get(); final Optional endpointPid = currentOptions.getCloudEndpointPid(); if (!endpointPid.isPresent()) { return; } final Filter filter; try { filter = Utils.createFilter(CloudEndpoint.class, endpointPid.get()); } catch (final Exception e) { getLogger().warn("invalid cloud endpoint pid", e); return; } this.tracker = new ServiceTracker<>(this.context, filter, new Customizer()); this.tracker.open(); } private class Customizer implements ServiceTrackerCustomizer { @Override public RawMqttCloudEndpoint addingService(final ServiceReference reference) { final CloudEndpoint service = AbstractStackComponent.this.context.getService(reference); if (service == null) { return null; } if (!(service instanceof RawMqttCloudEndpoint)) { AbstractStackComponent.this.context.ungetService(reference); return null; } final RawMqttCloudEndpoint trackedService = (RawMqttCloudEndpoint) service; setCloudEndpoint(trackedService); return trackedService; } @Override public void modifiedService(final ServiceReference reference, final RawMqttCloudEndpoint service) { // do nothing } @Override public void removedService(final ServiceReference reference, final RawMqttCloudEndpoint service) { unsetCloudEndpoint(service); AbstractStackComponent.this.context.ungetService(reference); } } public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onDisconnected)); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onConnectionLost)); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(Utils.catchAll(CloudConnectionListener::onConnectionEstablished)); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/Property.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnecton.raw.mqtt.util; import java.util.Map; import java.util.function.Function; import java.util.function.Predicate; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; public class Property { protected final String key; protected final T defaultValue; protected final Class valueType; public Property(final String key, final T defaultValue) { this(key, defaultValue, defaultValue.getClass()); } public Property(final String key, final Class valueType) { this(key, null, valueType); } private Property(final String key, final T defaultValue, final Class valueType) { this.key = key; this.defaultValue = defaultValue; this.valueType = valueType; } public String getKey() { return this.key; } public T getDefaultValue() { return this.defaultValue; } @SuppressWarnings("unchecked") public T get(final Map properties) throws KuraException { try { return (T) properties.get(this.key); } catch (final Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, null, null, "invalid property value for " + this.key, e); } } @SuppressWarnings("unchecked") public T getOrDefault(final Map properties) throws KuraException { final Object value = properties.get(this.key); if (this.valueType.isInstance(value)) { return (T) value; } return this.defaultValue; } public Property map(final Class valueType, final Function mapper) { final Property orig = this; return new Property(this.key, this.defaultValue != null ? mapper.apply(this.defaultValue) : null, valueType) { @Override public U get(final Map properties) throws KuraException { return mapper.apply(orig.get(properties)); } @Override public U getOrDefault(final Map properties) { try { return mapper.apply(orig.getOrDefault(properties)); } catch (final Exception e) { return this.defaultValue; } } }; } public Property validate(final Predicate validator) { final Property orig = this; return new Property(this.key, this.defaultValue, this.valueType) { @Override public T get(final Map properties) throws KuraException { final T value = orig.get(properties); if (!validator.test(value)) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, null, null, "Validation failed for property " + this.key); } return value; } @Override public T getOrDefault(final Map properties) throws KuraException { final T value = orig.getOrDefault(properties); if (!validator.test(value)) { return this.defaultValue; } return value; } }; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/StackComponentOptions.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnecton.raw.mqtt.util; import java.util.Map; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class StackComponentOptions { private static final Logger logger = LoggerFactory.getLogger(StackComponentOptions.class); private static final Property CLOUD_ENDPOINT_SERVICE_PID = new Property<>( CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), String.class); private final Optional cloudEndpointPid; private final Optional componentOptions; public StackComponentOptions(final Map properties, final OptionsFactory factory) { this.cloudEndpointPid = extractCloudEndpointPid(properties); this.componentOptions = factory.tryBuild(properties); } private static Optional extractCloudEndpointPid(final Map properties) { try { return Optional.of(CLOUD_ENDPOINT_SERVICE_PID.get(properties)); } catch (final Exception e) { logger.warn("cloud endpoint pid not set"); return Optional.empty(); } } public Optional getCloudEndpointPid() { return this.cloudEndpointPid; } public Optional getComponentOptions() { return this.componentOptions; } public interface OptionsFactory { public T build(final Map properties) throws KuraException; public default Optional tryBuild(final Map properties) { try { return Optional.of(this.build(properties)); } catch (final Exception e) { logger.warn("invalid publishing properties", e); return Optional.empty(); } } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.raw.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnecton/raw/mqtt/util/Utils.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnecton.raw.mqtt.util; import java.util.function.Consumer; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class Utils { private static final Logger logger = LoggerFactory.getLogger(Utils.class); private Utils() { } public static Consumer catchAll(final Consumer consumer) { return item -> { try { consumer.accept(item); } catch (final Exception e) { logger.warn("unexpected exception", e); } }; } public static Filter createFilter(final Class type, final String kuraServicePid) throws InvalidSyntaxException { final StringBuilder builder = new StringBuilder(); builder.append("(&(") // .append(Constants.OBJECTCLASS) // .append('=') // .append(type.getName()) // .append(")(") // .append(ConfigurationService.KURA_SERVICE_PID) // .append('=') // .append(kuraServicePid) // .append("))"); return FrameworkUtil.createFilter(builder.toString()); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/.gitignore ================================================ /target /bin .vscode generated-sources/ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Sparkplug MQTT Cloud Connection Provider Bundle-SymbolicName: org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider Bundle-Version: 2.0.0.qualifier Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: com.google.gson;version="[2.7,3.0)", com.google.protobuf;version="4.30.2", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.cloud;version="[1.1,2.0)", org.eclipse.kura.cloudconnection;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.factory;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.listener;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber;version="[1.0,1.1)", org.eclipse.kura.cloudconnection.subscriber.listener;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.crypto;version="[1.3,2.0)", org.eclipse.kura.data;version="[1.0,2.0)", org.eclipse.kura.data.listener;version="[1.0,2.0)", org.eclipse.kura.data.transport.listener;version="[1.0,2.0)", org.eclipse.kura.message;version="[1.4,2.0)", org.eclipse.kura.ssl;version="[2.1,3.0)", org.eclipse.kura.type;version="[1.1,2.0)", org.osgi.framework;version="1.8.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.3.1", org.osgi.util.tracker;version="[1.5,2.0)", org.slf4j;version="1.7.36" Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/*.xml Bundle-Vendor: Eclipse Kura Bundle-License: Eclipse Public License v2.0 Bundle-ClassPath: ., lib/org.eclipse.paho.client.mqttv3-1.2.1.k2.jar ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugCloudConnectionFactory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugCloudEndpoint.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugDataTransport.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugDevice.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/SparkplugSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/OSGI-INF/metatype/org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/build.properties ================================================ source.. = src/main/java/,\ generated-sources/src/main/java/ output.. = target/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html,\ lib/ ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider.test/target/site/jacoco-aggregate/jacoco.xml ${project.basedir}/generated-sources/**/* ${project.basedir}/generated-sources/**/* 4.30.2 org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider 2.0.0-SNAPSHOT eclipse-plugin org.eclipse.paho org.eclipse.paho.client.mqttv3 kr.motd.maven os-maven-plugin 1.7.1 initialize detect org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1 com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} generate-sources compile org.codehaus.mojo build-helper-maven-plugin 3.3.0 generate-sources add-source ${project.basedir}/generated-sources/src/main/java maven-resources-plugin 3.0.2 copy-protobuf-resource generate-sources copy-resources ${project.basedir}/generated-sources/src/main ${project.build.directory}/generated-sources/protobuf/ org.apache.maven.plugins maven-checkstyle-plugin ${project.basedir}/generated-sources/**/* ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/device/SparkplugDevice.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.device; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugMessageType; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.SparkplugCloudEndpointTracker; import org.eclipse.kura.configuration.ConfigurableComponent; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SparkplugDevice implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudDeliveryListener { private static final Logger logger = LoggerFactory.getLogger(SparkplugDevice.class); public static final String KEY_MESSAGE_TYPE = "message.type"; public static final String KEY_DEVICE_ID = "device.id"; private String deviceId; private SparkplugCloudEndpointTracker endpointTracker; private Optional sparkplugCloudEndpoint = Optional.empty(); private final Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private final Set cloudDeliveryListeners = new CopyOnWriteArraySet<>(); private final ExecutorService executorService = Executors.newCachedThreadPool(); private Set deviceMetrics = new HashSet<>(); /* * ConfigurableComponent APIs */ public void activate(final ComponentContext componentContext, final Map properties) throws InvalidSyntaxException { String endpointPid = (String) properties .get(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value()); this.endpointTracker = new SparkplugCloudEndpointTracker(componentContext.getBundleContext(), this::setSparkplugCloudEndpoint, this::unsetSparkplugCloudEndpoint, endpointPid); this.endpointTracker.startEndpointTracker(); update(properties); } public void update(final Map properties) { this.deviceId = (String) properties.get(KEY_DEVICE_ID); if (Objects.isNull(this.deviceId) || this.deviceId.trim().isEmpty()) { throw new IllegalArgumentException("Property '" + KEY_DEVICE_ID + "' cannot be null or empty"); } this.deviceMetrics.clear(); logger.info("Sparkplug Device {} - Updated device ID", this.deviceId); } public void deactivate() { logger.info("Sparkplug Device {} - Deactivating", this.deviceId); this.endpointTracker.stopEndpointTracker(); logger.debug("Sparkplug Device {} - Shutting down executor service", this.deviceId); this.executorService.shutdownNow(); logger.info("Sparkplug Device {} - Deactivated", this.deviceId); } /* * CloudConnectionListener APIs */ @Override public void onDisconnected() { this.deviceMetrics.clear(); this.cloudConnectionListeners.forEach(listener -> this.executorService.execute(listener::onDisconnected)); } @Override public void onConnectionLost() { this.deviceMetrics.clear(); this.cloudConnectionListeners.forEach(listener -> this.executorService.execute(listener::onConnectionLost)); } @Override public void onConnectionEstablished() { this.deviceMetrics.clear(); this.cloudConnectionListeners .forEach(listener -> this.executorService.execute(listener::onConnectionEstablished)); } /* * CloudPublisher APIs */ @Override public synchronized String publish(final KuraMessage message) throws KuraException { if (!this.sparkplugCloudEndpoint.isPresent()) { throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "Missing SparkplugCloudEndpoint reference"); } final Map newMessageProperties = new HashMap<>(); newMessageProperties.put(KEY_DEVICE_ID, this.deviceId); if (this.deviceMetrics.isEmpty() || !this.deviceMetrics.equals(message.getPayload().metricNames())) { this.deviceMetrics.clear(); this.deviceMetrics.addAll(message.getPayload().metricNames()); newMessageProperties.put(KEY_MESSAGE_TYPE, SparkplugMessageType.DBIRTH); logger.info("Sparkplug Device {} - Metrics set changed, publishing DBIRTH", this.deviceId); } else { newMessageProperties.put(KEY_MESSAGE_TYPE, SparkplugMessageType.DDATA); } return this.sparkplugCloudEndpoint.get().publish(new KuraMessage(message.getPayload(), newMessageProperties)); } @Override public void registerCloudConnectionListener(final CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(final CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void registerCloudDeliveryListener(final CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(final CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } /* * CloudDeliveryListener APIs */ @Override public void onMessageConfirmed(final String messageId) { this.cloudDeliveryListeners.forEach(listener -> this.executorService .execute(() -> InvocationUtils.callSafely(listener::onMessageConfirmed, messageId))); } /* * Utils */ private synchronized void setSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) { this.sparkplugCloudEndpoint = Optional.of(endpoint); this.sparkplugCloudEndpoint.get().registerCloudConnectionListener(this); this.sparkplugCloudEndpoint.get().registerCloudDeliveryListener(this); } private synchronized void unsetSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) { if (this.sparkplugCloudEndpoint.isPresent() && this.sparkplugCloudEndpoint.get() == endpoint) { this.sparkplugCloudEndpoint.get().unregisterCloudConnectionListener(this); this.sparkplugCloudEndpoint.get().unregisterCloudDeliveryListener(this); this.sparkplugCloudEndpoint = Optional.empty(); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SeqCounter.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint; public class SeqCounter { private int seq = 1; // start from 1 since 0 is reserved for BIRTH messages public synchronized void next() { if (this.seq == 255) { this.seq = 1; } else { this.seq = this.seq + 1; } } public synchronized int getCurrent() { return this.seq; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SparkplugCloudEndpoint.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraDisconnectException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.cloud.CloudConnectionEstablishedEvent; import org.eclipse.kura.cloud.CloudConnectionLostEvent; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.device.SparkplugDevice; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugMessageType; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugPayloads; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugTopics; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber.SparkplugSubscriber; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.data.DataService; import org.eclipse.kura.data.listener.DataServiceListener; import org.osgi.service.event.Event; import org.osgi.service.event.EventAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.InvalidProtocolBufferException; public class SparkplugCloudEndpoint implements ConfigurableComponent, CloudEndpoint, CloudConnectionManager, DataServiceListener { public static final String PLACEHOLDER_GROUP_ID = "placeholder.group.id"; public static final String PLACEHOLDER_NODE_ID = "placeholder.node.id"; private static final Logger logger = LoggerFactory.getLogger(SparkplugCloudEndpoint.class); private Set cloudConnectionListeners = new HashSet<>(); private Set cloudDeliveryListeners = new HashSet<>(); private String kuraServicePid; private SeqCounter seqCounter = new SeqCounter(); private SubscriptionsMap subscriptions = new SubscriptionsMap(); private ExecutorService executorService = Executors.newCachedThreadPool(); /* * Activation APIs */ private DataService dataService; private EventAdmin eventAdmin; public void setDataService(final DataService dataService) { this.dataService = dataService; } public void setEventAdmin(final EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public void activate(final Map properties) { this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("{} - Activating", this.kuraServicePid); this.dataService.addDataServiceListener(this); update(); logger.info("{} - Activated", this.kuraServicePid); } public void update() { logger.info("{} - Updating", this.kuraServicePid); this.seqCounter = new SeqCounter(); logger.debug("{} - seq number reset to {}", this.kuraServicePid, this.seqCounter.getCurrent()); logger.info("{} - Updated", this.kuraServicePid); } public void deactivate() { logger.info("{} - Deactivating", this.kuraServicePid); try { disconnect(); } catch (KuraDisconnectException e) { logger.info("{} - Error disconnecting", this.kuraServicePid, e); } this.executorService.shutdownNow(); logger.info("{} - Deactivated", this.kuraServicePid); } /* * CloudEndpoint APIs */ @Override public String publish(final KuraMessage message) throws KuraException { Map messageProperties = message.getProperties(); if (!messageProperties.containsKey(SparkplugDevice.KEY_MESSAGE_TYPE) || !messageProperties.containsKey(SparkplugDevice.KEY_DEVICE_ID)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "KuraMessage has a missing property between message.type and device.id"); } SparkplugMessageType type = (SparkplugMessageType) messageProperties.get(SparkplugDevice.KEY_MESSAGE_TYPE); String deviceId = (String) messageProperties.get(SparkplugDevice.KEY_DEVICE_ID); logger.debug("{} - Sending message with seq: {}", this.kuraServicePid, this.seqCounter.getCurrent()); byte[] sparkplugPayload = SparkplugPayloads.getSparkplugDevicePayload(this.seqCounter.getCurrent(), message.getPayload()); this.seqCounter.next(); if (type == SparkplugMessageType.DBIRTH) { return publishInternal( SparkplugTopics.getDeviceBirthTopic(PLACEHOLDER_GROUP_ID, PLACEHOLDER_NODE_ID, deviceId), sparkplugPayload, 0, false, 0); } if (type == SparkplugMessageType.DDATA) { return publishInternal( SparkplugTopics.getDeviceDataTopic(PLACEHOLDER_GROUP_ID, PLACEHOLDER_NODE_ID, deviceId), sparkplugPayload, 0, false, 7); } return null; } private String publishInternal(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException { int id = this.dataService.publish(topic, payload, qos, retain, priority); if (qos == 0) { return null; } return String.valueOf(id); } @Override public void registerSubscriber(Map subscriptionProperties, CloudSubscriberListener cloudSubscriberListener) { String topicFilter = (String) subscriptionProperties.get(SparkplugSubscriber.KEY_TOPIC_FILTER); int qos = (int) subscriptionProperties.get(SparkplugSubscriber.KEY_QOS); this.subscriptions.add(topicFilter, qos, cloudSubscriberListener); subscribeIfConnected(topicFilter, qos); logger.info("{} - Added subscription for {}", this.kuraServicePid, cloudSubscriberListener.getClass().getSimpleName()); } @Override public void unregisterSubscriber(CloudSubscriberListener cloudSubscriberListener) { this.subscriptions.remove(cloudSubscriberListener).forEach(this::unsubscribeIfConnected); logger.info("{} - Removed subscription for {}", this.kuraServicePid, cloudSubscriberListener.getClass().getSimpleName()); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { logger.debug("{} - Adding CloudDeliveryListener {}", this.kuraServicePid, cloudDeliveryListener.getClass().getName()); this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { logger.debug("{} - Removing CloudDeliveryListener {}", this.kuraServicePid, cloudDeliveryListener.getClass().getName()); this.cloudDeliveryListeners.remove(cloudDeliveryListener); } /* * CloudConnectionManager APIs */ @Override public void connect() throws KuraConnectException { this.dataService.connect(); } @Override public void disconnect() throws KuraDisconnectException { this.dataService.disconnect(0); } @Override public boolean isConnected() { return this.dataService.isConnected(); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { logger.debug("{} - Adding CloudConnectionListener {}", this.kuraServicePid, cloudConnectionListener.getClass().getName()); this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { logger.debug("{} - Removing CloudConnectionListener {}", this.kuraServicePid, cloudConnectionListener.getClass().getName()); this.cloudConnectionListeners.remove(cloudConnectionListener); } /* * DataServiceListener APIs */ @Override public void onConnectionEstablished() { logger.debug("{} - Connection estabilished", this.kuraServicePid); this.cloudConnectionListeners .forEach(listener -> InvocationUtils.callSafely(listener::onConnectionEstablished)); postConnectionChangeEvent(true); this.seqCounter = new SeqCounter(); this.subscriptions.getSubscriptionRecords() .forEach(subscription -> subscribeIfConnected(subscription.getTopicFilter(), subscription.getQos())); } @Override public void onDisconnecting() { // nothing to do } @Override public void onDisconnected() { logger.debug("{} - Disconnected", this.kuraServicePid); this.cloudConnectionListeners.forEach(listener -> InvocationUtils.callSafely(listener::onDisconnected)); postConnectionChangeEvent(false); } @Override public void onConnectionLost(Throwable cause) { logger.debug("{} - Connection lost", this.kuraServicePid); this.cloudConnectionListeners.forEach(listener -> InvocationUtils.callSafely(listener::onConnectionLost)); postConnectionChangeEvent(false); } @Override public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) { logger.debug("{} - Message arrived on topic {}, forwarding to registered subscribers", this.kuraServicePid, topic); for (CloudSubscriberListener listener : this.subscriptions.getMatchingListeners(topic, qos)) { try { KuraMessage message = new KuraMessage(SparkplugPayloads.getKuraPayload(payload)); this.executorService.execute(() -> InvocationUtils.callSafely(listener::onMessageArrived, message)); } catch (InvalidProtocolBufferException e) { logger.error("{} - Error parsing received SparkplugPayload to KuraPayload", this.kuraServicePid, e); } } } @Override public void onMessagePublished(int messageId, String topic) { // nothing to do } @Override public void onMessageConfirmed(int messageId, String topic) { logger.debug("{} - Message with ID {} confirmed", this.kuraServicePid, messageId); this.cloudDeliveryListeners.forEach( listener -> InvocationUtils.callSafely(listener::onMessageConfirmed, String.valueOf(messageId))); } /* * Utilities */ private void postConnectionChangeEvent(final boolean isConnected) { logger.debug("{} - Posting connection changed event", this.kuraServicePid); Map eventProperties = new HashMap<>(); eventProperties.put("cloud.service.pid", this.kuraServicePid); Event event = isConnected ? new CloudConnectionEstablishedEvent(eventProperties) : new CloudConnectionLostEvent(eventProperties); this.eventAdmin.postEvent(event); } private synchronized void subscribeIfConnected(String topicFilter, int qos) { try { if (isConnected()) { this.dataService.subscribe(topicFilter, qos); } } catch (KuraException e) { logger.error("{} - Error subscribing to topic " + topicFilter + " with QoS " + qos, this.kuraServicePid, e); } } private synchronized void unsubscribeIfConnected(String topic) { try { if (isConnected()) { this.dataService.unsubscribe(topic); } } catch (KuraException e) { logger.error("{} - Error unsubscribing from topic {}", this.kuraServicePid, topic); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SubscriptionRecord.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint; import org.eclipse.paho.client.mqttv3.MqttTopic; public class SubscriptionRecord { private final String topicFilter; private final Integer qos; public SubscriptionRecord(String topicFilter, int qos) { this.topicFilter = topicFilter; this.qos = qos; } public String getTopicFilter() { return this.topicFilter; } public Integer getQos() { return this.qos; } public boolean matches(String topic, int qos) { return this.qos <= qos && MqttTopic.isMatched(this.topicFilter, topic); } @Override public boolean equals(Object other) { if (other == this) { return true; } if (!(other instanceof SubscriptionRecord)) { return false; } SubscriptionRecord otherRecord = (SubscriptionRecord) other; return otherRecord.getTopicFilter().equals(this.topicFilter) && otherRecord.getQos().equals(this.qos); } @Override public int hashCode() { final int prime = 7; int result = 1; result = prime * result + this.topicFilter.hashCode(); result = prime * result + this.qos.hashCode(); return result; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/endpoint/SubscriptionsMap.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; public class SubscriptionsMap { private Map> subscriptions = new HashMap<>(); public void add(String topicFilter, int qos, CloudSubscriberListener listener) { SubscriptionRecord subscription = new SubscriptionRecord(topicFilter, qos); Set listeners = this.subscriptions.computeIfAbsent(subscription, key -> new CopyOnWriteArraySet()); listeners.add(listener); } public List remove(CloudSubscriberListener listener) { List topicsToUnsubscribe = new ArrayList<>(); this.subscriptions.entrySet().removeIf(entry -> { entry.getValue().remove(listener); if (entry.getValue().isEmpty()) { topicsToUnsubscribe.add(entry.getKey().getTopicFilter()); return true; } return false; }); return topicsToUnsubscribe; } public List getMatchingListeners(String topic, int qos) { List result = new ArrayList<>(); this.subscriptions.forEach((subscription, listeners) -> { if (subscription.matches(topic, qos)) { result.addAll(listeners); } }); return result; } public Set getSubscriptionRecords() { return this.subscriptions.keySet(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/factory/SparkplugCloudConnectionFactory.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentConstants; public class SparkplugCloudConnectionFactory implements CloudConnectionFactory { private static final String FACTORY_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.factory.SparkplugCloudConnectionFactory"; private static final String CLOUD_ENDPOINT_FACTORY_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint"; private static final String DATA_SERVICE_FACTORY_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport"; private static final String CLOUD_ENDPOINT_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint"; private static final String DATA_SERVICE_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.data.SparkplugDataService"; private static final String DATA_TRANSPORT_SERVICE_PID = "org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport.SparkplugDataTransport"; private static final String DATA_SERVICE_REFERENCE_NAME = "DataService" + ComponentConstants.REFERENCE_TARGET_SUFFIX; private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = "DataTransportService" + ComponentConstants.REFERENCE_TARGET_SUFFIX; private static final String REFERENCE_TARGET_VALUE_FORMAT = "(" + ConfigurationService.KURA_SERVICE_PID + "=%s)"; private ConfigurationService configurationService; public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } @Override public String getFactoryPid() { return CLOUD_ENDPOINT_FACTORY_PID; } @Override public void createConfiguration(String pid) throws KuraException { String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID); String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID); // CloudEndpoint Map cloudEndpointProperties = new HashMap<>(); cloudEndpointProperties.put(DATA_SERVICE_REFERENCE_NAME, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid)); cloudEndpointProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID); cloudEndpointProperties.put(DATA_TRANSPORT_SERVICE_REFERENCE_NAME, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid)); this.configurationService.createFactoryConfiguration(CLOUD_ENDPOINT_FACTORY_PID, pid, cloudEndpointProperties, false); // DataService Map dataServiceProperties = new HashMap<>(); dataServiceProperties.put(DATA_TRANSPORT_SERVICE_REFERENCE_NAME, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid)); this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid, dataServiceProperties, false); // DataTransportService this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID, dataTransportServicePid, null, true); } @Override public List getStackComponentsPids(String pid) throws KuraException { String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID); String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID); List stackComponentPids = new LinkedList<>(); stackComponentPids.add(pid); stackComponentPids.add(dataServicePid); stackComponentPids.add(dataTransportServicePid); return stackComponentPids; } @Override public void deleteConfiguration(String pid) throws KuraException { String dataServicePid = getStackPidWithSuffix(pid, DATA_SERVICE_PID); String dataTransportServicePid = getStackPidWithSuffix(pid, DATA_TRANSPORT_SERVICE_PID); this.configurationService.deleteFactoryConfiguration(pid, false); this.configurationService.deleteFactoryConfiguration(dataServicePid, false); this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true); } @Override public Set getManagedCloudConnectionPids() throws KuraException { final BundleContext context = FrameworkUtil.getBundle(SparkplugCloudConnectionFactory.class).getBundleContext(); try { return context .getServiceReferences(CloudEndpoint.class, "(service.factoryPid=" + CLOUD_ENDPOINT_FACTORY_PID + ")") .stream().map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)) .collect(Collectors.toSet()); } catch (InvalidSyntaxException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e); } } private String getStackPidWithSuffix(String userPid, String componentPid) throws KuraException { if (!userPid.startsWith(CLOUD_ENDPOINT_PID)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", userPid); } String[] parts = userPid.split("-"); if (parts.length > 1) { return componentPid + "-" + parts[1]; } else { return componentPid; } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugBProtobufPayloadBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.message; import java.math.BigInteger; import java.util.Date; import org.eclipse.tahu.protobuf.SparkplugBProto.DataType; import org.eclipse.tahu.protobuf.SparkplugBProto.Payload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.protobuf.ByteString; public class SparkplugBProtobufPayloadBuilder { private static final Logger logger = LoggerFactory.getLogger(SparkplugBProtobufPayloadBuilder.class); public static final String BDSEQ_METRIC_NAME = "bdSeq"; private Payload.Builder payloadBuilder = Payload.newBuilder(); public SparkplugBProtobufPayloadBuilder withMetric(String name, Object value, long timestamp) { DataType sparkplugDataType = DataType.Unknown; if (value instanceof Boolean) { sparkplugDataType = DataType.Boolean; } if (value instanceof byte[]) { sparkplugDataType = DataType.Bytes; } if (value instanceof Double) { sparkplugDataType = DataType.Double; } if (value instanceof Float) { sparkplugDataType = DataType.Float; } if (value instanceof Byte) { sparkplugDataType = DataType.Int8; } if (value instanceof Short) { sparkplugDataType = DataType.Int16; } if (value instanceof Integer) { sparkplugDataType = DataType.Int32; } if (value instanceof Long) { sparkplugDataType = DataType.Int64; } if (value instanceof String) { sparkplugDataType = DataType.String; } if (value instanceof Date) { sparkplugDataType = DataType.DateTime; } if (value instanceof BigInteger) { sparkplugDataType = DataType.UInt64; } logger.debug("Converting Java Type: {} to Sparkplug.DataType: {}", value.getClass().getName(), sparkplugDataType); return this.withMetric(name, value, sparkplugDataType, timestamp); } public SparkplugBProtobufPayloadBuilder withMetric(String name, Object value, DataType dataType, long timestamp) { Payload.Metric.Builder metricBuilder = Payload.Metric.newBuilder(); metricBuilder.setName(name); metricBuilder.setDatatype(dataType.getNumber()); metricBuilder.setTimestamp(timestamp); switch (dataType) { case Boolean: metricBuilder.setBooleanValue((Boolean) value); break; case Bytes: metricBuilder.setBytesValue(ByteString.copyFrom((byte[]) value)); break; case Double: metricBuilder.setDoubleValue((Double) value); break; case Float: metricBuilder.setFloatValue((Float) value); break; case Int8: metricBuilder.setIntValue((Byte) value); break; case Int16: metricBuilder.setIntValue((Short) value); break; case Int32: metricBuilder.setIntValue((Integer) value); break; case Int64: metricBuilder.setLongValue((Long) value); break; case String: case Text: case UUID: metricBuilder.setStringValue((String) value); break; case DateTime: metricBuilder.setLongValue(((Date) value).getTime()); break; case UInt8: metricBuilder.setIntValue(Short.toUnsignedInt((Short) value)); break; case UInt16: metricBuilder.setIntValue((int) Integer.toUnsignedLong((Integer) value)); break; case UInt32: metricBuilder.setLongValue(Long.parseUnsignedLong(Long.toUnsignedString((Long) value))); break; case UInt64: metricBuilder.setLongValue(((BigInteger) value).longValue()); break; case DataSet: case Template: case PropertySet: case PropertySetList: case File: case BooleanArray: case DateTimeArray: case UInt8Array: case UInt64Array: case UInt32Array: case UInt16Array: case StringArray: case Int8Array: case Int64Array: case Int32Array: case Int16Array: case FloatArray: case DoubleArray: case Unknown: default: throw new UnsupportedOperationException("DataType " + dataType.toString() + " not implemented"); } this.payloadBuilder.addMetrics(metricBuilder.build()); return this; } public SparkplugBProtobufPayloadBuilder withBdSeq(long bdSeq, long timestamp) { Payload.Metric.Builder bdSeqMetric = Payload.Metric.newBuilder(); bdSeqMetric.setName(BDSEQ_METRIC_NAME); bdSeqMetric.setLongValue(bdSeq); bdSeqMetric.setDatatype(DataType.Int64.getNumber()); bdSeqMetric.setTimestamp(timestamp); this.payloadBuilder.addMetrics(bdSeqMetric.build()); return this; } public SparkplugBProtobufPayloadBuilder withSeq(long seq) { this.payloadBuilder.setSeq(seq); return this; } public SparkplugBProtobufPayloadBuilder withTimestamp(long timestamp) { this.payloadBuilder.setTimestamp(timestamp); return this; } public SparkplugBProtobufPayloadBuilder withBody(byte[] body) { this.payloadBuilder.setBody(ByteString.copyFrom(body)); return this; } public Payload buildPayload() { return this.payloadBuilder.build(); } public byte[] build() { return this.buildPayload().toByteArray(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugMessageType.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.message; public enum SparkplugMessageType { NBIRTH, NDEATH, NCMD, DBIRTH, DDEATH, DDATA, DCMD, STATE } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugPayloads.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.message; import java.util.Date; import java.util.Map.Entry; import java.util.Objects; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraPosition; import org.eclipse.tahu.protobuf.SparkplugBProto.DataType; import org.eclipse.tahu.protobuf.SparkplugBProto.Payload; import org.eclipse.tahu.protobuf.SparkplugBProto.Payload.Metric; import com.google.protobuf.InvalidProtocolBufferException; public class SparkplugPayloads { public static final String NODE_CONTROL_REBIRTH_METRIC_NAME = "Node Control/Rebirth"; private SparkplugPayloads() { } public static byte[] getNodeDeathPayload(long bdSeq) { return new SparkplugBProtobufPayloadBuilder().withBdSeq(bdSeq, new Date().getTime()).build(); } public static byte[] getNodeBirthPayload(long bdSeq, long seq) { long timestamp = new Date().getTime(); SparkplugBProtobufPayloadBuilder payloadBuilder = new SparkplugBProtobufPayloadBuilder(); payloadBuilder.withBdSeq(bdSeq, timestamp); payloadBuilder.withMetric(NODE_CONTROL_REBIRTH_METRIC_NAME, false, DataType.Boolean, timestamp); payloadBuilder.withSeq(seq); payloadBuilder.withTimestamp(timestamp); return payloadBuilder.build(); } public static boolean getBooleanMetric(String metricName, byte[] rawSparkplugPayload) throws InvalidProtocolBufferException, NoSuchFieldException { Payload payload = Payload.parseFrom(rawSparkplugPayload); for (Metric metric : payload.getMetricsList()) { if (metric.getName().equals(metricName)) { return metric.getBooleanValue(); } } throw new NoSuchFieldException("Metric " + metricName + " not found in payload"); } public static byte[] getSparkplugDevicePayload(final long seq, final KuraPayload kuraPayload) { SparkplugBProtobufPayloadBuilder payloadBuilder = new SparkplugBProtobufPayloadBuilder(); byte[] payloadBody = kuraPayload.getBody(); if (Objects.nonNull(payloadBody)) { payloadBuilder.withBody(payloadBody); } Date kuraTimestamp = kuraPayload.getTimestamp(); long timestamp = Objects.nonNull(kuraTimestamp) ? kuraTimestamp.getTime() : new Date().getTime(); payloadBuilder.withTimestamp(timestamp); for (Entry metric : kuraPayload.metrics().entrySet()) { payloadBuilder.withMetric(metric.getKey(), metric.getValue(), timestamp); } KuraPosition position = kuraPayload.getPosition(); if (Objects.nonNull(position)) { addMetricIfNonNull(payloadBuilder, "kura.position.altitude", position.getAltitude(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.latitude", position.getLatitude(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.longitude", position.getLongitude(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.heading", position.getHeading(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.precision", position.getPrecision(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.satellites", position.getSatellites(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.speed", position.getSpeed(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.status", position.getStatus(), timestamp); addMetricIfNonNull(payloadBuilder, "kura.position.timestamp", position.getTimestamp(), timestamp); } payloadBuilder.withSeq(seq); payloadBuilder.withTimestamp(timestamp); return payloadBuilder.build(); } public static KuraPayload getKuraPayload(byte[] rawSparkplugPayload) throws InvalidProtocolBufferException { KuraPayload kuraPayload = new KuraPayload(); Payload sparkplugPayload = Payload.parseFrom(rawSparkplugPayload); for (Metric metric : sparkplugPayload.getMetricsList()) { kuraPayload.addMetric(metric.getName(), getMetricValue(metric)); } if (sparkplugPayload.hasBody()) { kuraPayload.setBody(sparkplugPayload.getBody().toByteArray()); } if (Objects.nonNull(sparkplugPayload.getSeq())) { kuraPayload.addMetric("seq", sparkplugPayload.getSeq()); } if (Objects.nonNull(sparkplugPayload.getTimestamp())) { kuraPayload.setTimestamp(new Date(sparkplugPayload.getTimestamp())); } return kuraPayload; } private static void addMetricIfNonNull(SparkplugBProtobufPayloadBuilder payloadBuilder, String name, Object value, long timestamp) { if (Objects.nonNull(value)) { payloadBuilder.withMetric(name, value, timestamp); } } private static Object getMetricValue(Metric metric) { switch (metric.getValueCase()) { case BOOLEAN_VALUE: return metric.getBooleanValue(); case BYTES_VALUE: return metric.getBytesValue().toByteArray(); case DATASET_VALUE: return metric.getDatasetValue().toByteArray(); case DOUBLE_VALUE: return metric.getDoubleValue(); case EXTENSION_VALUE: return metric.getExtensionValue().toByteArray(); case FLOAT_VALUE: return metric.getFloatValue(); case INT_VALUE: return metric.getIntValue(); case LONG_VALUE: return metric.getLongValue(); case STRING_VALUE: return metric.getStringValue(); case TEMPLATE_VALUE: return metric.getTemplateValue().toByteArray(); case VALUE_NOT_SET: default: return null; } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/message/SparkplugTopics.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.message; public class SparkplugTopics { private SparkplugTopics() { } private static final String NAMESPACE = "spBv1.0"; // Edge Node topics public static String getNodeBirthTopic(String groupId, String nodeId) { return getTopic(groupId, SparkplugMessageType.NBIRTH.toString(), nodeId); } public static String getNodeDeathTopic(String groupId, String nodeId) { return getTopic(groupId, SparkplugMessageType.NDEATH.toString(), nodeId); } public static String getNodeCommandTopic(String groupId, String nodeId) { return getTopic(groupId, SparkplugMessageType.NCMD.toString(), nodeId); } // Device topics public static String getDeviceBirthTopic(String groupId, String nodeId, String deviceId) { return getTopic(groupId, SparkplugMessageType.DBIRTH.toString(), nodeId, deviceId); } public static String getDeviceDeathTopic(String groupId, String nodeId, String deviceId) { return getTopic(groupId, SparkplugMessageType.DDEATH.toString(), nodeId, deviceId); } public static String getDeviceDataTopic(String groupId, String nodeId, String deviceId) { return getTopic(groupId, SparkplugMessageType.DDATA.toString(), nodeId, deviceId); } public static String getDeviceCommandTopic(String groupId, String nodeId, String deviceId) { return getTopic(groupId, SparkplugMessageType.DCMD.toString(), nodeId, deviceId); } // Host Application topics public static String getStateTopic(String hostId) { return getTopic(SparkplugMessageType.STATE.toString(), hostId); } private static String getTopic(String... args) { StringBuilder topicBuilder = new StringBuilder(NAMESPACE); for (String arg : args) { topicBuilder.append("/"); topicBuilder.append(arg); } return topicBuilder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/subscriber/SparkplugSubscriber.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.subscriber; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.SparkplugCloudEndpointTracker; import org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber; import org.eclipse.kura.cloudconnection.subscriber.listener.CloudSubscriberListener; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.paho.client.mqttv3.MqttTopic; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SparkplugSubscriber implements ConfigurableComponent, CloudSubscriber, CloudSubscriberListener, CloudConnectionListener { private static final Logger logger = LoggerFactory.getLogger(SparkplugSubscriber.class); public static final String KEY_TOPIC_FILTER = "topic.filter"; public static final String KEY_QOS = "qos"; private Optional sparkplugCloudEndpoint = Optional.empty(); private SparkplugCloudEndpointTracker endpointTracker; private final ExecutorService executorService = Executors.newCachedThreadPool(); private Set cloudSubscriberListeners = new CopyOnWriteArraySet<>(); private Set cloudConnectionListeners = new CopyOnWriteArraySet<>(); private String kuraServicePid; private String topicFilter; private int qos; /* * Activation APIs */ public void activate(final ComponentContext componentContext, final Map properties) throws InvalidSyntaxException { this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("{} - Activating", this.kuraServicePid); String endpointPid = (String) properties .get(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value()); this.endpointTracker = new SparkplugCloudEndpointTracker(componentContext.getBundleContext(), this::setSparkplugCloudEndpoint, this::unsetSparkplugCloudEndpoint, endpointPid); update(properties); logger.info("{} - Activated", this.kuraServicePid); } public void update(final Map properties) throws InvalidSyntaxException { logger.info("{} - Updating", this.kuraServicePid); this.topicFilter = (String) properties.get(KEY_TOPIC_FILTER); this.qos = (int) properties.get(KEY_QOS); MqttTopic.validate(this.topicFilter, true); this.endpointTracker.stopEndpointTracker(); this.endpointTracker.startEndpointTracker(); logger.info("{} - Updated", this.kuraServicePid); } public void deactivate() { logger.info("{} - Deactivating", this.kuraServicePid); this.endpointTracker.stopEndpointTracker(); logger.debug("{} - Shutting down executor service", this.kuraServicePid); this.executorService.shutdownNow(); logger.info("{} - Deactivated", this.kuraServicePid); } /* * CloudSubscriber APIs */ @Override public void registerCloudSubscriberListener(CloudSubscriberListener listener) { this.cloudSubscriberListeners.add(listener); } @Override public void unregisterCloudSubscriberListener(CloudSubscriberListener listener) { this.cloudSubscriberListeners.remove(listener); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } /* * CloudSubscriberListener APIs */ @Override public void onMessageArrived(KuraMessage message) { this.cloudSubscriberListeners.forEach(listener -> this.executorService .execute(() -> InvocationUtils.callSafely(listener::onMessageArrived, message))); } /* * CloudConnectionListener APIs */ @Override public void onDisconnected() { this.cloudConnectionListeners.forEach( listener -> this.executorService.execute(() -> InvocationUtils.callSafely(listener::onDisconnected))); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach( listener -> this.executorService.execute(() -> InvocationUtils.callSafely(listener::onConnectionLost))); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(listener -> this.executorService .execute(() -> InvocationUtils.callSafely(listener::onConnectionEstablished))); } /* * Utils */ private synchronized void setSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) { Map properties = new HashMap<>(); properties.put(KEY_TOPIC_FILTER, this.topicFilter); properties.put(KEY_QOS, this.qos); this.sparkplugCloudEndpoint = Optional.of(endpoint); this.sparkplugCloudEndpoint.get().registerSubscriber(properties, this); } private synchronized void unsetSparkplugCloudEndpoint(SparkplugCloudEndpoint endpoint) { if (this.sparkplugCloudEndpoint.isPresent() && this.sparkplugCloudEndpoint.get() == endpoint) { this.sparkplugCloudEndpoint.get().unregisterSubscriber(this); this.sparkplugCloudEndpoint = Optional.empty(); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/BdSeqCounter.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport; public class BdSeqCounter { private int bdSeq = -1; // first invocation of next should return 0 public synchronized void next() { if (this.bdSeq == 255) { this.bdSeq = 0; } else { this.bdSeq = this.bdSeq + 1; } } public synchronized int getCurrent() { return this.bdSeq; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugDataTransport.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraNotConnectedException; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.data.DataTransportService; import org.eclipse.kura.data.DataTransportToken; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.eclipse.kura.ssl.SslManagerService; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SparkplugDataTransport implements ConfigurableComponent, DataTransportService, MqttCallback { private static final Logger logger = LoggerFactory.getLogger(SparkplugDataTransport.class); private String kuraServicePid; private String sessionId; private SparkplugMqttClient client; private SparkplugDataTransportOptions options; private Set dataTransportListeners = new HashSet<>(); private ExecutorService executorService; private SslManagerService sslManagerService; private CryptoService cryptoService; /* * Activation APIs */ public synchronized void setSslManagerService(SslManagerService sslManagerService) { this.sslManagerService = sslManagerService; update(); } public synchronized void unsetSslManagerService(SslManagerService sslManagerService) { if (this.sslManagerService == sslManagerService) { this.sslManagerService = null; update(); } } public synchronized void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public synchronized void activate(Map properties) { this.kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); logger.info("{} - Activating", this.kuraServicePid); update(properties); logger.info("{} - Activated", this.kuraServicePid); } public synchronized void update(Map properties) { try { this.options = new SparkplugDataTransportOptions(properties, this.cryptoService); update(); } catch (KuraException ke) { logger.error("{} - Error in configuration properties", this.kuraServicePid, ke); } } public synchronized void deactivate() { logger.info("{} - Deactivating", this.kuraServicePid); disconnect(0); logger.info("{} - Deactivated", this.kuraServicePid); } private void update() { if (Objects.nonNull(this.options)) { logger.info("{} - Updating", this.kuraServicePid); boolean wasConnected = isConnected(); this.dataTransportListeners .forEach(listener -> InvocationUtils.callSafely(listener::onConfigurationUpdating, wasConnected)); try { applyConfiguration(wasConnected); } catch (KuraConnectException ke) { logger.error("{} - Error reconnecting after configuration update", this.kuraServicePid, ke); } } } private void applyConfiguration(boolean wasConnected) throws KuraConnectException { if (wasConnected) { disconnect(0); } this.sessionId = getBrokerUrl() + "-" + getClientId(); this.client = new SparkplugMqttClient(this.options, this, this.dataTransportListeners, this.sslManagerService); if (wasConnected) { connect(); } this.dataTransportListeners .forEach(listener -> InvocationUtils.callSafely(listener::onConfigurationUpdated, wasConnected)); logger.info("{} - Updated", this.kuraServicePid); } /* * DataTransportService APIs */ @Override public void connect() throws KuraConnectException { if (isConnected()) { throw new IllegalStateException("MQTT client is already connected"); } this.client.establishSession(true); stopExecutorService(); this.executorService = Executors.newSingleThreadExecutor(); logger.debug("{} - Initialized message dispatcher executor", this.kuraServicePid); } @Override public boolean isConnected() { return Objects.nonNull(this.client) && this.client.isSessionEstablished(); } @Override public String getBrokerUrl() { return Objects.nonNull(this.client) ? this.client.getConnectedServer() : ""; } @Override public synchronized String getAccountName() { return ""; } @Override public String getUsername() { return this.options.getUsername(); } @Override public String getClientId() { return this.options.getClientId(); } @Override public void disconnect(long quiesceTimeout) { stopExecutorService(); if (Objects.nonNull(this.client)) { this.client.terminateSession(true, quiesceTimeout); } } @Override public void subscribe(String topic, int qos) throws KuraException { checkConnected(); this.client.subscribe(topic, qos); } @Override public void unsubscribe(String topic) throws KuraException { checkConnected(); this.client.unsubscribe(topic); } @Override public DataTransportToken publish(String completeTopic, byte[] payload, int qos, boolean retain) throws KuraException { checkConnected(); String topic = completeTopic.replace(SparkplugCloudEndpoint.PLACEHOLDER_GROUP_ID, this.options.getGroupId()) .replace(SparkplugCloudEndpoint.PLACEHOLDER_NODE_ID, this.options.getNodeId()); IMqttDeliveryToken deliveryToken = this.client.publish(topic, payload, qos, retain); if (qos > 0) { return new DataTransportToken(deliveryToken.getMessageId(), this.sessionId); } return null; } @Override public void addDataTransportListener(DataTransportListener listener) { logger.debug("{} - Adding DataTransportListener {}", this.kuraServicePid, listener.getClass().getName()); this.dataTransportListeners.add(listener); } @Override public void removeDataTransportListener(DataTransportListener listener) { logger.debug("{} - Removing DataTransportListener {}", this.kuraServicePid, listener.getClass().getName()); this.dataTransportListeners.remove(listener); } /* * MqttCallback APIs */ @Override public void connectionLost(Throwable arg0) { logger.info("{} - Connection lost", this.kuraServicePid); this.client.handleConnectionLost(); this.dataTransportListeners.forEach(listener -> InvocationUtils.callSafely(listener::onConnectionLost, arg0)); } @Override public void deliveryComplete(IMqttDeliveryToken deliveryToken) { try { if (deliveryToken.getMessage().getQos() > 0) { DataTransportToken dataTransportToken = new DataTransportToken(deliveryToken.getMessageId(), this.sessionId); this.dataTransportListeners .forEach(listener -> InvocationUtils.callSafely(listener::onMessageConfirmed, dataTransportToken)); } } catch (MqttException e) { logger.error("{} - Error processing MQTTDeliveryToken", this.kuraServicePid, e); } } @Override public void messageArrived(String topic, MqttMessage message) { logger.debug("{} - Message arrived on topic {} with QoS {}", this.kuraServicePid, topic, message.getQos()); this.executorService.submit(() -> this.dataTransportListeners.forEach(listener -> listener .onMessageArrived(topic, message.getPayload(), message.getQos(), message.isRetained()))); this.executorService.submit(this.client.getMessageDispatcher(topic, message)); } /* * Utils */ private void checkConnected() throws KuraNotConnectedException { if (!isConnected()) { throw new KuraNotConnectedException("MQTT client is not connected"); } } private void stopExecutorService() { if (Objects.nonNull(this.executorService)) { logger.debug("{} - Shutting down message dispatcher executor", this.kuraServicePid); this.executorService.shutdownNow(); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugDataTransportOptions.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; public class SparkplugDataTransportOptions { public static final String KEY_GROUP_ID = "group.id"; public static final String KEY_NODE_ID = "node.id"; public static final String KEY_PRIMARY_HOST_APPLICATION_ID = "primary.host.application.id"; public static final String KEY_SERVER_URIS = "server.uris"; public static final String KEY_CLIENT_ID = "client.id"; public static final String KEY_USERNAME = "username"; public static final String KEY_PASSWORD = "password"; public static final String KEY_KEEP_ALIVE = "keep.alive"; public static final String KEY_CONNECTION_TIMEOUT = "connection.timeout"; private final String groupId; private final String nodeId; private final Optional primaryHostApplicationId; private final List servers; private final MqttConnectOptions connectionOptions = new MqttConnectOptions(); private final String clientId; public SparkplugDataTransportOptions(final Map properties, final CryptoService cryptoService) throws KuraException { this.groupId = getMandatoryString(KEY_GROUP_ID, properties); this.nodeId = getMandatoryString(KEY_NODE_ID, properties); this.primaryHostApplicationId = getOptionalString(KEY_PRIMARY_HOST_APPLICATION_ID, properties); this.servers = getServersList(KEY_SERVER_URIS, properties); this.clientId = getMandatoryString(KEY_CLIENT_ID, properties); Optional username = getOptionalString(KEY_USERNAME, properties); Optional password = getOptionalPassword(KEY_PASSWORD, properties); if (username.isPresent()) { this.connectionOptions.setUserName(username.get()); } if (password.isPresent()) { this.connectionOptions.setPassword(cryptoService.decryptAes(password.get().getPassword())); } this.connectionOptions.setKeepAliveInterval(getMandatoryInt(KEY_KEEP_ALIVE, properties)); this.connectionOptions.setConnectionTimeout(getMandatoryInt(KEY_CONNECTION_TIMEOUT, properties)); this.connectionOptions.setCleanSession(true); this.connectionOptions.setAutomaticReconnect(false); } public String getGroupId() { return this.groupId; } public String getNodeId() { return this.nodeId; } public Optional getPrimaryHostApplicationId() { return this.primaryHostApplicationId; } public List getServers() { return this.servers; } public MqttConnectOptions getMqttConnectOptions() { return this.connectionOptions; } public String getClientId() { return this.clientId; } public String getUsername() { return this.connectionOptions.getUserName(); } public long getConnectionTimeoutMs() { return this.connectionOptions.getConnectionTimeout() * 1000L; } private String getMandatoryString(String key, Map map) throws KuraException { String value = (String) map.get(key); if (Objects.isNull(value) || value.isEmpty()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + " cannot be empty or null"); } return value; } private int getMandatoryInt(String key, Map map) throws KuraException { Integer value = (Integer) map.get(key); if (Objects.isNull(value)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + " cannot be null"); } return value; } private Optional getOptionalString(String key, Map map) { String value = (String) map.get(key); if (Objects.isNull(value) || value.isEmpty()) { return Optional.empty(); } else { return Optional.of(value); } } private Optional getOptionalPassword(String key, Map map) { String value = (String) map.get(key); if (Objects.isNull(value) || value.isEmpty()) { return Optional.empty(); } else { return Optional.of(new Password(value)); } } private List getServersList(String key, Map map) throws KuraException { String spaceSeparatedList = (String) map.get(key); if (Objects.isNull(spaceSeparatedList) || spaceSeparatedList.isEmpty()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + " cannot be empty or null"); } List result = new ArrayList<>(); String[] uris = spaceSeparatedList.split(" "); for (String server : uris) { if (server.endsWith("/") || server.isEmpty()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, key + " items cannot be empty, or end with '/', or contain a path"); } result.add(server); } return result; } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/transport/SparkplugMqttClient.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.transport; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Random; import java.util.Set; import javax.net.SocketFactory; import org.eclipse.kura.KuraConnectException; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugPayloads; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.message.SparkplugTopics; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils.InvocationUtils; import org.eclipse.kura.data.transport.listener.DataTransportListener; import org.eclipse.kura.ssl.SslManagerService; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.IMqttToken; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.protobuf.InvalidProtocolBufferException; public class SparkplugMqttClient { private static final Logger logger = LoggerFactory.getLogger(SparkplugMqttClient.class); private List servers; private Iterator serversIterator; private String clientId; private MqttConnectOptions options; private MqttCallback callback; private Set listeners; private String groupId; private String nodeId; private Optional primaryHostId; private long connectionTimeoutMs; private MqttAsyncClient client; private BdSeqCounter bdSeqCounter = new BdSeqCounter(); private long lastStateTimestamp = 0; private Random randomDelayGenerator = new Random(); private SslManagerService sslManagerService; private SessionStatus sessionStatus = new Terminated(); /* * State management */ private abstract class SessionStatus { public abstract SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException; public abstract SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout); public abstract SessionStatus confirmSession(); SessionStatus toEstablishing(boolean shouldConnectClient) throws KuraConnectException { try { if (shouldConnectClient) { newClientConnection(); } subscribe(SparkplugTopics.getNodeCommandTopic(SparkplugMqttClient.this.groupId, SparkplugMqttClient.this.nodeId), 1); if (SparkplugMqttClient.this.primaryHostId.isPresent()) { subscribe(SparkplugTopics.getStateTopic(SparkplugMqttClient.this.primaryHostId.get()), 1); } else { return toEstablished(); } } catch (MqttException | GeneralSecurityException | IOException e) { SparkplugMqttClient.this.bdSeqCounter = new BdSeqCounter(); throw new KuraConnectException(e); } return new Establishing(); } SessionStatus toTerminated(boolean shouldDisconnectClient, long quiesceTimeout) { try { SparkplugMqttClient.this.listeners .forEach(listener -> InvocationUtils.callSafely(listener::onDisconnecting)); if (SparkplugMqttClient.this.sessionStatus instanceof Established) { sendEdgeNodeDeath(); } if (shouldDisconnectClient) { disconnectClient(quiesceTimeout); } SparkplugMqttClient.this.listeners .forEach(listener -> InvocationUtils.callSafely(listener::onDisconnected)); } catch (MqttException e) { logger.error("Error terminating Sparkplug Edge Node session", e); return SparkplugMqttClient.this.sessionStatus; } return new Terminated(); } SessionStatus toEstablished() { sendEdgeNodeBirth(); SparkplugMqttClient.this.listeners .forEach(listener -> InvocationUtils.callSafely(listener::onConnectionEstablished, true)); return new Established(); } private void newClientConnection() throws MqttException, GeneralSecurityException, IOException { SparkplugMqttClient.this.bdSeqCounter.next(); setWillMessage(); logger.debug("bdSeq: {}", SparkplugMqttClient.this.bdSeqCounter.getCurrent()); try { long randomDelay = SparkplugMqttClient.this.randomDelayGenerator.nextInt(5000); logger.info("Randomly delaying connect by {} ms", randomDelay); Thread.sleep(randomDelay); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } SparkplugMqttClient.this.client = new MqttAsyncClient(getNextServer(), SparkplugMqttClient.this.clientId, new MemoryPersistence()); SparkplugMqttClient.this.client.setCallback(SparkplugMqttClient.this.callback); IMqttToken token = SparkplugMqttClient.this.client.connect(SparkplugMqttClient.this.options); token.waitForCompletion(SparkplugMqttClient.this.connectionTimeoutMs); logger.debug("Client connected"); } private void disconnectClient(long quiesceTimeout) throws MqttException { if (SparkplugMqttClient.this.client.isConnected()) { IMqttToken token = SparkplugMqttClient.this.client.disconnect(quiesceTimeout); token.waitForCompletion(SparkplugMqttClient.this.connectionTimeoutMs); } logger.debug("Client disconnected"); } private void setWillMessage() { String topic = SparkplugTopics.getNodeDeathTopic(SparkplugMqttClient.this.groupId, SparkplugMqttClient.this.nodeId); byte[] payload = SparkplugPayloads.getNodeDeathPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent()); SparkplugMqttClient.this.options.setWill(topic, payload, 1, false); } private void sendEdgeNodeBirth() { String topic = SparkplugTopics.getNodeBirthTopic(SparkplugMqttClient.this.groupId, SparkplugMqttClient.this.nodeId); byte[] payload = SparkplugPayloads.getNodeBirthPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent(), 0); publish(topic, payload, 0, false); logger.debug("Published Edge Node BIRTH with bdSeq {}", SparkplugMqttClient.this.bdSeqCounter.getCurrent()); } private void sendEdgeNodeDeath() { String topic = SparkplugTopics.getNodeDeathTopic(SparkplugMqttClient.this.groupId, SparkplugMqttClient.this.nodeId); byte[] payload = SparkplugPayloads.getNodeDeathPayload(SparkplugMqttClient.this.bdSeqCounter.getCurrent()); publish(topic, payload, 0, false); logger.debug("Published Edge Node DEATH with bdSeq {}", SparkplugMqttClient.this.bdSeqCounter.getCurrent()); } private String getNextServer() throws GeneralSecurityException, IOException { String server; if (SparkplugMqttClient.this.serversIterator.hasNext()) { server = SparkplugMqttClient.this.serversIterator.next(); } else { SparkplugMqttClient.this.serversIterator = SparkplugMqttClient.this.servers.iterator(); server = SparkplugMqttClient.this.serversIterator.next(); } setSocketFactory(server); logger.info("Selecting next server {} from {}", server, SparkplugMqttClient.this.servers); return server; } private void setSocketFactory(String server) throws GeneralSecurityException, IOException { if (server.startsWith("ssl")) { SparkplugMqttClient.this.options .setSocketFactory(SparkplugMqttClient.this.sslManagerService.getSSLSocketFactory()); } else { SparkplugMqttClient.this.options.setSocketFactory(SocketFactory.getDefault()); } } } private class Terminated extends SessionStatus { @Override public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException { return toEstablishing(shouldConnectClient); } @Override public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) { return this; } @Override public SessionStatus confirmSession() { return this; } } private class Establishing extends SessionStatus { @Override public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException { return this; } @Override public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) { return toTerminated(shouldDisconnectClient, quiesceTimeout); } @Override public SessionStatus confirmSession() { return toEstablished(); } } private class Established extends SessionStatus { @Override public SessionStatus establishSession(boolean shouldConnectClient) throws KuraConnectException { return this; } @Override public SessionStatus terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) { return toTerminated(shouldDisconnectClient, quiesceTimeout); } @Override public SessionStatus confirmSession() { return toEstablished(); } } /* * Public methods */ public SparkplugMqttClient(SparkplugDataTransportOptions options, MqttCallback callback, Set listeners, SslManagerService sslManagerService) { this.servers = options.getServers(); this.serversIterator = this.servers.iterator(); this.clientId = options.getClientId(); this.options = options.getMqttConnectOptions(); this.callback = callback; this.listeners = listeners; this.groupId = options.getGroupId(); this.nodeId = options.getNodeId(); this.primaryHostId = options.getPrimaryHostApplicationId(); this.connectionTimeoutMs = options.getConnectionTimeoutMs(); this.sslManagerService = sslManagerService; logger.info( "Sparkplug MQTT client updated" + "\n\tServers: {}" + "\n\tClient ID: {}" + "\n\tGroup ID: {}" + "\n\tNode ID: {}" + "\n\tPrimary Host Application ID: {}" + "\n\tConnection Timeout (ms): {}", this.servers, this.clientId, this.groupId, this.nodeId, this.primaryHostId, this.connectionTimeoutMs); } public synchronized boolean isSessionEstablished() { return this.sessionStatus instanceof Established && Objects.nonNull(this.client) && this.client.isConnected(); } public synchronized void handleConnectionLost() { doSessionTransition(new Terminated()); } public synchronized void establishSession(boolean shouldConnectClient) throws KuraConnectException { logger.debug("Requested session establishment"); doSessionTransition(this.sessionStatus.establishSession(shouldConnectClient)); } public synchronized void terminateSession(boolean shouldDisconnectClient, long quiesceTimeout) { logger.debug("Requested session termination"); doSessionTransition(this.sessionStatus.terminateSession(shouldDisconnectClient, quiesceTimeout)); } public synchronized void confirmSession() { logger.debug("Requested session confirmation"); doSessionTransition(this.sessionStatus.confirmSession()); } public synchronized IMqttDeliveryToken publish(String topic, byte[] payload, int qos, boolean isRetained) { try { logger.info("Publishing message on topic {} with QoS {} and retain {}", topic, qos, isRetained); return this.client.publish(topic, payload, qos, isRetained); } catch (MqttException e) { logger.error("Error publishing to topic {} with QoS {}", topic, qos, e); } return null; } public synchronized void subscribe(String topic, int qos) { try { IMqttToken token = this.client.subscribe(topic, qos); token.waitForCompletion(this.connectionTimeoutMs); logger.info("Subscribed to topic {} with QoS {}", topic, qos); } catch (MqttException e) { logger.error("Error subscribing to topic {} with QoS {}", topic, qos, e); } } public synchronized void unsubscribe(String topic) { try { IMqttToken token = this.client.unsubscribe(topic); token.waitForCompletion(this.connectionTimeoutMs); logger.info("Unsubscribed from topic {}", topic); } catch (MqttException e) { logger.error("Error unsubscribing from topic {}", topic, e); } } public synchronized String getConnectedServer() { return isSessionEstablished() ? this.client.getCurrentServerURI() : this.servers.toString(); } public synchronized Runnable getMessageDispatcher(String topic, MqttMessage message) { return () -> dispatchMessage(topic, message); } /* * Private methods */ private void doSessionTransition(SessionStatus newStatus) { String from = this.sessionStatus.getClass().getSimpleName(); String to = newStatus.getClass().getSimpleName(); if (!from.equals(to)) { logger.info("Sparkplug session: {} -> {}", from, to); this.sessionStatus = newStatus; } } private synchronized void dispatchMessage(String topic, MqttMessage message) { boolean isValidStateMessage = this.primaryHostId.isPresent() && topic.equals(SparkplugTopics.getStateTopic(this.primaryHostId.get())); boolean isValidNcmdMessage = topic.equals(SparkplugTopics.getNodeCommandTopic(this.groupId, this.nodeId)); try { if (isValidStateMessage) { dispatchStateMessage(message.getPayload()); } else if (isValidNcmdMessage) { dispatchNcmdMessage(message.getPayload()); } } catch (Exception e) { logger.error("Error dispatching arrived message", e); } } private void dispatchStateMessage(byte[] payload) throws KuraConnectException { logger.debug("Handling STATE message"); JsonElement json = JsonParser.parseString(new String(payload, StandardCharsets.UTF_8)); boolean isOnline = json.getAsJsonObject().get("online").getAsBoolean(); long timestamp = json.getAsJsonObject().get("timestamp").getAsLong(); if (this.lastStateTimestamp <= timestamp) { this.lastStateTimestamp = timestamp; if (isOnline) { logger.info("Primary Host Application is online"); confirmSession(); } else { logger.info("Primary Host Application is offline"); terminateSession(true, 0); establishSession(true); } } } private void dispatchNcmdMessage(byte[] payload) throws KuraConnectException { logger.debug("Handling NCMD message"); try { boolean nodeRebirth = SparkplugPayloads.getBooleanMetric(SparkplugPayloads.NODE_CONTROL_REBIRTH_METRIC_NAME, payload); if (nodeRebirth) { logger.debug("{} requested", SparkplugPayloads.NODE_CONTROL_REBIRTH_METRIC_NAME); terminateSession(false, 0); establishSession(false); } } catch (InvalidProtocolBufferException e) { logger.error("Error processing payload for NCMD message", e); } catch (NoSuchFieldException e) { logger.debug("NMCD message ignored, it does not contain any Node Control/Rebirth metric"); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/utils/InvocationUtils.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class InvocationUtils { private static final String ERROR_MESSAGE_FORMAT = "An error occurred in listener '%s'"; private InvocationUtils() { } private static final Logger logger = LoggerFactory.getLogger(InvocationUtils.class); public static void callSafely(Runnable f) { try { f.run(); } catch (Exception e) { logger.error(String.format(ERROR_MESSAGE_FORMAT, f.getClass().getName()), e); } } public static void callSafely(Consumer f, T argument) { try { f.accept(argument); } catch (Exception e) { logger.error(String.format(ERROR_MESSAGE_FORMAT, f.getClass().getName()), e); } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/java/org/eclipse/kura/cloudconnection/sparkplug/mqtt/utils/SparkplugCloudEndpointTracker.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.cloudconnection.sparkplug.mqtt.utils; import java.util.Objects; import java.util.function.Consumer; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.sparkplug.mqtt.endpoint.SparkplugCloudEndpoint; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; public class SparkplugCloudEndpointTracker { private final BundleContext bundleContext; private ServiceTracker cloudConnectionManagerTracker; private final Consumer serviceAddedConsumer; private final Consumer serviceRemovedConsumer; private final String endpointPid; public SparkplugCloudEndpointTracker(BundleContext bundleContext, Consumer serviceAddedConsumer, Consumer serviceRemovedConsumer, String endpointPid) { this.bundleContext = bundleContext; this.serviceAddedConsumer = serviceAddedConsumer; this.serviceRemovedConsumer = serviceRemovedConsumer; this.endpointPid = endpointPid; } public void startEndpointTracker() throws InvalidSyntaxException { String filterString = String.format("(&(%s=%s)(kura.service.pid=%s))", Constants.OBJECTCLASS, CloudConnectionManager.class.getName(), this.endpointPid); final Filter filter = this.bundleContext.createFilter(filterString); this.cloudConnectionManagerTracker = new ServiceTracker<>(this.bundleContext, filter, new SparkplugCloudEndpointTrackerCustomizer()); this.cloudConnectionManagerTracker.open(); } public void stopEndpointTracker() { if (Objects.nonNull(this.cloudConnectionManagerTracker)) { this.cloudConnectionManagerTracker.close(); } } private class SparkplugCloudEndpointTrackerCustomizer implements ServiceTrackerCustomizer { @Override public synchronized CloudConnectionManager addingService( final ServiceReference reference) { CloudConnectionManager cloudConnectionManager = SparkplugCloudEndpointTracker.this.bundleContext .getService(reference); if (cloudConnectionManager instanceof SparkplugCloudEndpoint) { SparkplugCloudEndpointTracker.this.serviceAddedConsumer .accept((SparkplugCloudEndpoint) cloudConnectionManager); return cloudConnectionManager; } else { SparkplugCloudEndpointTracker.this.bundleContext.ungetService(reference); } return null; } @Override public synchronized void removedService(final ServiceReference reference, final CloudConnectionManager service) { if (service instanceof SparkplugCloudEndpoint) { SparkplugCloudEndpointTracker.this.serviceRemovedConsumer.accept((SparkplugCloudEndpoint) service); } } @Override public synchronized void modifiedService(final ServiceReference reference, final CloudConnectionManager service) { // Not needed } } } ================================================ FILE: kura/org.eclipse.kura.cloudconnection.sparkplug.mqtt.provider/src/main/proto/sparkplug_b.proto ================================================ // * Copyright (c) 2015, 2018 Cirrus Link Solutions and others // * // * This program and the accompanying materials are made available under the // * terms of the Eclipse Public License 2.0 which is available at // * http://www.eclipse.org/legal/epl-2.0. // * // * SPDX-License-Identifier: EPL-2.0 // * // * Contributors: // * Cirrus Link Solutions - initial implementation // // To compile: // cd client_libraries/java // protoc --proto_path=../../ --java_out=src/main/java ../../sparkplug_b.proto // syntax = "proto2"; package org.eclipse.tahu.protobuf; option java_package = "org.eclipse.tahu.protobuf"; option java_outer_classname = "SparkplugBProto"; enum DataType { // Indexes of Data Types // Unknown placeholder for future expansion. Unknown = 0; // Basic Types Int8 = 1; Int16 = 2; Int32 = 3; Int64 = 4; UInt8 = 5; UInt16 = 6; UInt32 = 7; UInt64 = 8; Float = 9; Double = 10; Boolean = 11; String = 12; DateTime = 13; Text = 14; // Additional Metric Types UUID = 15; DataSet = 16; Bytes = 17; File = 18; Template = 19; // Additional PropertyValue Types PropertySet = 20; PropertySetList = 21; // Array Types Int8Array = 22; Int16Array = 23; Int32Array = 24; Int64Array = 25; UInt8Array = 26; UInt16Array = 27; UInt32Array = 28; UInt64Array = 29; FloatArray = 30; DoubleArray = 31; BooleanArray = 32; StringArray = 33; DateTimeArray = 34; } message Payload { message Template { message Parameter { optional string name = 1; optional uint32 type = 2; oneof value { uint32 int_value = 3; uint64 long_value = 4; float float_value = 5; double double_value = 6; bool boolean_value = 7; string string_value = 8; ParameterValueExtension extension_value = 9; } message ParameterValueExtension { extensions 1 to max; } } optional string version = 1; // The version of the Template to prevent mismatches repeated Metric metrics = 2; // Each metric includes a name, datatype, and optionally a value repeated Parameter parameters = 3; optional string template_ref = 4; // MUST be a reference to a template definition if this is an instance (i.e. the name of the template definition) - MUST be omitted for template definitions optional bool is_definition = 5; extensions 6 to max; } message DataSet { message DataSetValue { oneof value { uint32 int_value = 1; uint64 long_value = 2; float float_value = 3; double double_value = 4; bool boolean_value = 5; string string_value = 6; DataSetValueExtension extension_value = 7; } message DataSetValueExtension { extensions 1 to max; } } message Row { repeated DataSetValue elements = 1; extensions 2 to max; // For third party extensions } optional uint64 num_of_columns = 1; repeated string columns = 2; repeated uint32 types = 3; repeated Row rows = 4; extensions 5 to max; // For third party extensions } message PropertyValue { optional uint32 type = 1; optional bool is_null = 2; oneof value { uint32 int_value = 3; uint64 long_value = 4; float float_value = 5; double double_value = 6; bool boolean_value = 7; string string_value = 8; PropertySet propertyset_value = 9; PropertySetList propertysets_value = 10; // List of Property Values PropertyValueExtension extension_value = 11; } message PropertyValueExtension { extensions 1 to max; } } message PropertySet { repeated string keys = 1; // Names of the properties repeated PropertyValue values = 2; extensions 3 to max; } message PropertySetList { repeated PropertySet propertyset = 1; extensions 2 to max; } message MetaData { // Bytes specific metadata optional bool is_multi_part = 1; // General metadata optional string content_type = 2; // Content/Media type optional uint64 size = 3; // File size, String size, Multi-part size, etc optional uint64 seq = 4; // Sequence number for multi-part messages // File metadata optional string file_name = 5; // File name optional string file_type = 6; // File type (i.e. xml, json, txt, cpp, etc) optional string md5 = 7; // md5 of data // Catchalls and future expansion optional string description = 8; // Could be anything such as json or xml of custom properties extensions 9 to max; } message Metric { optional string name = 1; // Metric name - should only be included on birth optional uint64 alias = 2; // Metric alias - tied to name on birth and included in all later DATA messages optional uint64 timestamp = 3; // Timestamp associated with data acquisition time optional uint32 datatype = 4; // DataType of the metric/tag value optional bool is_historical = 5; // If this is historical data and should not update real time tag optional bool is_transient = 6; // Tells consuming clients such as MQTT Engine to not store this as a tag optional bool is_null = 7; // If this is null - explicitly say so rather than using -1, false, etc for some datatypes. optional MetaData metadata = 8; // Metadata for the payload optional PropertySet properties = 9; oneof value { uint32 int_value = 10; uint64 long_value = 11; float float_value = 12; double double_value = 13; bool boolean_value = 14; string string_value = 15; bytes bytes_value = 16; // Bytes, File DataSet dataset_value = 17; Template template_value = 18; MetricValueExtension extension_value = 19; } message MetricValueExtension { extensions 1 to max; } } optional uint64 timestamp = 1; // Timestamp at message sending time repeated Metric metrics = 2; // Repeated forever - no limit in Google Protobufs optional uint64 seq = 3; // Sequence number optional string uuid = 4; // UUID to track message type in terms of schema definitions optional bytes body = 5; // To optionally bypass the whole definition above extensions 6 to max; // For third party extensions } ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/.gitignore ================================================ /target /bin ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.configuration.change.manager Bundle-SymbolicName: org.eclipse.kura.configuration.change.manager;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: com.google.gson;version="2.7.0", org.eclipse.kura;version="[1.7,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.2,1.3)", org.eclipse.kura.message;version="[1.4,2.0)", org.osgi.framework;version="1.7.0", org.osgi.service.cm;version="1.4.0", org.osgi.util.tracker;version="[1.5,2.0)", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/OSGI-INF/metatype/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/OSGI-INF/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/,\ OSGI-INF/org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager.xml src.includes = about.html,\ about_files/ source.. = src/main/java/ ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.configuration.change.manager 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.configuration.change.manager.test/target/site/jacoco-aggregate/jacoco.xml org.apache.maven.plugins maven-checkstyle-plugin true ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ComponentsServiceTracker.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.configuration.change.manager; import java.util.HashSet; import java.util.Optional; import java.util.Set; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.util.tracker.ServiceTracker; @SuppressWarnings("rawtypes") public class ComponentsServiceTracker extends ServiceTracker { private final Set listeners; private static final String FILTER_EXCLUDE_CONF_CHANGE_MANAGER_FACTORY = "(!(service.factoryPid=org.eclipse.kura.configuration.change.manager.ConfigurationChangeManager))"; @SuppressWarnings("unchecked") public ComponentsServiceTracker(BundleContext context) throws InvalidSyntaxException { super(context, context.createFilter(FILTER_EXCLUDE_CONF_CHANGE_MANAGER_FACTORY), null); this.listeners = new HashSet<>(); } @SuppressWarnings({ "unchecked" }) @Override public Object addingService(ServiceReference ref) { Object service = super.addingService(ref); notifyListeners(ref); return service; } @Override public void modifiedService(ServiceReference reference, Object service) { notifyListeners(reference); } @SuppressWarnings({ "unchecked" }) @Override public void removedService(ServiceReference reference, Object service) { super.removedService(reference, service); notifyListeners(reference); } public void addServiceTrackerListener(ServiceTrackerListener listener) { this.listeners.add(listener); } public void removeServiceTrackerListener(ServiceTrackerListener listener) { this.listeners.remove(listener); } private void notifyListeners(ServiceReference ref) { Optional pid = getPidFromServiceReference(ref); if (pid.isPresent()) { for (ServiceTrackerListener listener : this.listeners) { listener.onConfigurationChanged(pid.get()); } } } private Optional getPidFromServiceReference(ServiceReference ref) { Optional pid = Optional.empty(); if (ref.getProperty(ConfigurationService.KURA_SERVICE_PID) != null) { pid = Optional.of((String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)); } else if (ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID) != null) { pid = Optional.of((String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID)); } else if (ref.getProperty(Constants.SERVICE_PID) != null) { pid = Optional.of((String) ref.getProperty(Constants.SERVICE_PID)); } return pid; } } ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ConfigurationChangeManager.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.configuration.change.manager; import java.util.Date; import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.message.KuraPayload; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.InvalidSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.gson.ExclusionStrategy; import com.google.gson.FieldAttributes; import com.google.gson.GsonBuilder; public class ConfigurationChangeManager implements ConfigurableComponent, ServiceTrackerListener { private static final Logger logger = LoggerFactory.getLogger(ConfigurationChangeManager.class); private class ChangedConfiguration { protected long timestamp; protected String pid; public ChangedConfiguration(String pid) { this.timestamp = new Date().getTime(); this.pid = pid; } @Override public boolean equals(Object other) { if (!(other instanceof ChangedConfiguration)) { return false; } return ((ChangedConfiguration) other).pid.equals(this.pid); } @Override public int hashCode() { return this.pid.hashCode(); } } private ConfigurationChangeManagerOptions options; private CloudPublisher cloudPublisher; private final ScheduledExecutorService scheduledSendQueueExecutor = Executors.newScheduledThreadPool(1); private ScheduledFuture futureSendQueue; private volatile boolean acceptNotifications = false; private final Queue notificationsQueue = new LinkedList<>(); private ComponentsServiceTracker serviceTracker; /* * Dependencies */ public void setCloudPublisher(CloudPublisher cloudPublisher) { this.cloudPublisher = cloudPublisher; } public void unsetCloudPublisher(CloudPublisher cloudPublisher) { if (this.cloudPublisher == cloudPublisher) { this.cloudPublisher = null; } } /* * Activation APIs */ public void activate(final Map properties) throws InvalidSyntaxException { logger.info("Activating ConfigurationChangeManager..."); this.acceptNotifications = false; BundleContext bundleContext = FrameworkUtil.getBundle(ConfigurationChangeManager.class).getBundleContext(); this.serviceTracker = new ComponentsServiceTracker(bundleContext); updated(properties); logger.info("Activating ConfigurationChangeManager... Done."); } public void updated(final Map properties) { logger.info("Updating ConfigurationChangeManager..."); this.options = new ConfigurationChangeManagerOptions(properties); if (this.options.isEnabled()) { this.acceptNotifications = true; this.serviceTracker.open(true); this.serviceTracker.addServiceTrackerListener(this); } else { this.acceptNotifications = false; this.serviceTracker.removeServiceTrackerListener(this); this.serviceTracker.close(); } logger.info("Updating ConfigurationChangeManager... Done."); } public void deactivate() { logger.info("Deactivating ConfigurationChangeManager..."); this.acceptNotifications = false; this.serviceTracker.removeServiceTrackerListener(this); this.serviceTracker.close(); logger.info("Deactivating ConfigurationChangeManager... Done."); } @Override public void onConfigurationChanged(String pid) { if (this.acceptNotifications) { ChangedConfiguration conf = new ChangedConfiguration(pid); if (this.notificationsQueue.contains(conf)) { this.notificationsQueue.remove(conf); } this.notificationsQueue.add(conf); if (this.futureSendQueue != null) { this.futureSendQueue.cancel(false); } this.futureSendQueue = this.scheduledSendQueueExecutor.schedule(this::sendQueue, this.options.getSendDelay(), TimeUnit.SECONDS); } } private byte[] createJsonFromNotificationsQueue() { GsonBuilder builder = new GsonBuilder(); builder.setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipClass(Class arg0) { return false; } @Override public boolean shouldSkipField(FieldAttributes arg0) { return arg0.getName().equals("timestamp"); } }); return builder.create().toJson(this.notificationsQueue).getBytes(); } private void sendQueue() { KuraPayload payload = new KuraPayload(); payload.setTimestamp(new Date(this.notificationsQueue.peek().timestamp)); payload.setBody(createJsonFromNotificationsQueue()); this.notificationsQueue.clear(); if (this.cloudPublisher != null) { try { this.cloudPublisher.publish(new KuraMessage(payload)); } catch (KuraException e) { logger.error("Error publishing configuration change event.", e); } } } } ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ConfigurationChangeManagerOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.configuration.change.manager; import java.util.Map; public class ConfigurationChangeManagerOptions { public static final String KEY_ENABLED = "enabled"; public static final String KEY_SEND_DELAY = "send.delay"; public static final boolean DEFAULT_ENABLED = false; public static final long DEFAULT_SEND_DELAY = 10; private final boolean enabled; private final long sendDelay; public ConfigurationChangeManagerOptions(Map properties) { this.enabled = (boolean) properties.getOrDefault(KEY_ENABLED, DEFAULT_ENABLED); this.sendDelay = (long) properties.getOrDefault(KEY_SEND_DELAY, DEFAULT_SEND_DELAY); } public boolean isEnabled() { return this.enabled; } public long getSendDelay() { return this.sendDelay; } } ================================================ FILE: kura/org.eclipse.kura.configuration.change.manager/src/main/java/org/eclipse/kura/configuration/change/manager/ServiceTrackerListener.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.configuration.change.manager; public interface ServiceTrackerListener { public void onConfigurationChanged(String pid); } ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/.gitignore ================================================ /target/ lib/* /lib/ ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Configurable container management component Bundle-SymbolicName: org.eclipse.kura.container.orchestration.provider Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Automatic-Module-Name: org.eclipse.kura.container.orchestration.provider Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: com.google.common.base;version="32.1.1", com.google.common.collect;version="32.1.1", com.google.common.escape;version="32.1.1", com.google.common.io;version="32.1.1", com.google.common.net;version="32.1.1", org.apache.commons.io;version="1.4.9999", org.apache.commons.lang3;version="3.17.0", org.eclipse.kura;version="[1.6,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.container.orchestration;version="[1.3,2.0)", org.eclipse.kura.container.orchestration.listener;version="[1.0,1.1)", org.eclipse.kura.crypto;version="[1.3,2.0]", org.eclipse.kura.util.configuration;version="[1.0,2.0)", com.fasterxml.jackson.annotation;version="2.19.2", com.fasterxml.jackson.core;version="2.19.2", com.fasterxml.jackson.core.type;version="2.19.2", com.fasterxml.jackson.databind;version="2.19.2", com.fasterxml.jackson.databind.node;version="2.19.2", com.fasterxml.jackson.databind.module;version="2.19.2", com.fasterxml.jackson.databind.deser;version="2.19.2", com.fasterxml.jackson.databind.deser.std;version="2.19.2", com.fasterxml.jackson.databind.type;version="2.19.2", org.bouncycastle.cert;version="1.78.1", org.bouncycastle.cert.jcajce;version="1.78.1", org.bouncycastle.jce.provider;version="1.78.1", org.bouncycastle.asn1;version="1.78.1", org.osgi.service.component;version="1.4.0", org.slf4j;version="1.7.25" Service-Component: OSGI-INF/component.xml Bundle-ClassPath: ., lib/commons-codec.jar, lib/commons-compress.jar, lib/docker-java-api.jar, lib/docker-java-core.jar, lib/docker-java-transport.jar, lib/docker-java-transport-httpclient5.jar, lib/httpclient5.jar, lib/httpcore5.jar, lib/httpcore5-h2.jar, lib/jna.jar ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/OSGI-INF/component.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/OSGI-INF/metatype/org.eclipse.kura.container.orchestration.provider.ContainerOrchestrationService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/build.properties ================================================ # # Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes bin.includes = .,\ META-INF/,\ OSGI-INF/,\ lib/commons-codec.jar,\ lib/commons-compress.jar,\ lib/docker-java-api.jar,\ lib/docker-java-core.jar,\ lib/docker-java-transport.jar,\ lib/docker-java-transport-httpclient5.jar,\ lib/httpclient5.jar,\ lib/httpcore5.jar,\ lib/httpcore5-h2.jar,\ lib/jna.jar,\ about.html,\ about_files/ src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.container.orchestration.provider 2.0.0-SNAPSHOT eclipse-plugin Management of docker container orchestration engine ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml com.github.docker-java docker-java com.github.docker-java docker-java-core com.github.docker-java docker-java-api com.github.docker-java docker-java-transport com.github.docker-java docker-java-transport-httpclient5 org.apache.httpcomponents.client5 httpclient5 org.apache.httpcomponents.core5 httpcore5 org.apache.httpcomponents.core5 httpcore5-h2 net.java.dev.jna jna org.apache.commons commons-compress commons-codec commons-codec maven-clean-plugin true lib/ false maven-dependency-plugin 3.8.1 copy-dependencies generate-sources copy-dependencies ${project.basedir}/lib docker-java, docker-java-core, docker-java-api, docker-java-transport, docker-java-transport-httpclient5, httpclient5, httpcore5, httpcore5-h2, jna, commons-codec, commons-compress true org.eclipse.m2e lifecycle-mapping 1.0.0 org.codehaus.mojo properties-maven-plugin [1.2.1,) read-project-properties org.codehaus.mojo build-helper-maven-plugin [1.9,) regex-property ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/ContainerOrchestrationServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.container.orchestration.provider.impl; import static java.util.Objects.isNull; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.container.orchestration.ContainerConfiguration; import org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor; import org.eclipse.kura.container.orchestration.ContainerOrchestrationService; import org.eclipse.kura.container.orchestration.ContainerState; import org.eclipse.kura.container.orchestration.ImageConfiguration; import org.eclipse.kura.container.orchestration.ImageInstanceDescriptor; import org.eclipse.kura.container.orchestration.ImageInstanceDescriptor.ImageInstanceDescriptorBuilder; import org.eclipse.kura.container.orchestration.PasswordRegistryCredentials; import org.eclipse.kura.container.orchestration.PortInternetProtocol; import org.eclipse.kura.container.orchestration.RegistryCredentials; import org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener; import org.eclipse.kura.container.orchestration.provider.impl.enforcement.AllowlistEnforcementMonitor; import org.eclipse.kura.crypto.CryptoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerCmd; import com.github.dockerjava.api.command.InspectImageResponse; import com.github.dockerjava.api.command.PullImageCmd; import com.github.dockerjava.api.command.PullImageResultCallback; import com.github.dockerjava.api.exception.NotModifiedException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.Container; import com.github.dockerjava.api.model.ContainerPort; import com.github.dockerjava.api.model.Device; import com.github.dockerjava.api.model.DeviceRequest; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.HostConfig; import com.github.dockerjava.api.model.Image; import com.github.dockerjava.api.model.InternetProtocol; import com.github.dockerjava.api.model.LogConfig; import com.github.dockerjava.api.model.LogConfig.LoggingType; import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Ports.Binding; import com.github.dockerjava.api.model.PullResponseItem; import com.github.dockerjava.api.model.RestartPolicy; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import com.google.common.collect.ImmutableList; public class ContainerOrchestrationServiceImpl implements ConfigurableComponent, ContainerOrchestrationService { private static final String PARAMETER_CANNOT_BE_NULL = "The provided parameter cannot be null"; private static final String UNABLE_TO_CONNECT_TO_DOCKER_CLI = "Unable to connect to docker cli"; private static final Logger logger = LoggerFactory.getLogger(ContainerOrchestrationServiceImpl.class); private static final String APP_ID = "org.eclipse.kura.container.orchestration.provider.ConfigurableDocker"; private ContainerOrchestrationServiceOptions currentConfig; private final Set dockerServiceListeners = new CopyOnWriteArraySet<>(); private final Set frameworkManagedContainers = new CopyOnWriteArraySet<>(); private DockerClient dockerClient; private CryptoService cryptoService; private AllowlistEnforcementMonitor allowlistEnforcementMonitor; private Map containerInstancesDigests = new HashMap<>(); public void setDockerClient(DockerClient dockerClient) { this.dockerClient = dockerClient; } public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void activate(Map properties) { logger.info("Bundle {} is starting with config!", APP_ID); if (!isNull(properties)) { updated(properties); } logger.info("Bundle {} has started with config!", APP_ID); } public void deactivate() { logger.info("Bundle {} is stopping!", APP_ID); if (testConnection()) { disconnect(); } logger.info("Bundle {} has stopped!", APP_ID); } public void updated(Map properties) { logger.info("Bundle {} is updating with config!", APP_ID); ContainerOrchestrationServiceOptions newProps = new ContainerOrchestrationServiceOptions(properties); if (!newProps.equals(this.currentConfig)) { this.currentConfig = newProps; logger.info("Connecting to docker "); if (!this.currentConfig.isEnabled()) { cleanUpDocker(); return; } if (this.allowlistEnforcementMonitor != null) { closeEnforcementMonitor(); } connect(); if (!testConnection()) { logger.error("Could not connect to docker CLI."); return; } logger.info("Connection Successful"); if (currentConfig.isEnforcementEnabled()) { try { startEnforcementMonitor(); } catch (Exception ex) { logger.error("Error starting enforcement monitor. Due to {}", ex.getMessage()); closeEnforcementMonitor(); logger.warn("Enforcement won't be active."); } enforceAlreadyRunningContainer(); } } logger.info("Bundle {} has updated with config!", APP_ID); } private void startEnforcementMonitor() { logger.info("Enforcement monitor starting..."); this.allowlistEnforcementMonitor = this.dockerClient.eventsCmd().withEventFilter("start") .exec(new AllowlistEnforcementMonitor(currentConfig.getEnforcementAllowlist(), this)); logger.info("Enforcement monitor starting...done."); } private void closeEnforcementMonitor() { if (this.allowlistEnforcementMonitor == null) { return; } try { logger.info("Enforcement monitor closing..."); this.allowlistEnforcementMonitor.close(); this.allowlistEnforcementMonitor.awaitCompletion(5, TimeUnit.SECONDS); this.allowlistEnforcementMonitor = null; logger.info("Enforcement monitor closing...done."); } catch (InterruptedException ex) { logger.error("Waited too long to close enforcement monitor, stopping it...", ex); Thread.currentThread().interrupt(); } catch (IOException ex) { logger.error("Failed to close enforcement monitor, stopping it...", ex); } } private void enforceAlreadyRunningContainer() { if (this.allowlistEnforcementMonitor == null) { logger.warn("Enforcement wasn't started. Check on running containers will not be performed."); return; } logger.info("Enforcement check on already running containers..."); this.allowlistEnforcementMonitor.enforceAllowlistFor(listContainerDescriptors()); logger.info("Enforcement check on already running containers...done"); } @Override public List listContainersIds() { if (!testConnection()) { throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI); } List containers = this.dockerClient.listContainersCmd().withShowAll(true).exec(); List result = new ArrayList<>(); for (Container cont : containers) { result.add(cont.getId()); } return result; } @Override public List listContainerDescriptors() { if (!testConnection()) { throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI); } List containers = this.dockerClient.listContainersCmd().withShowAll(true).exec(); List result = new ArrayList<>(); containers.forEach(container -> result.add(ContainerInstanceDescriptor.builder() .setContainerName(getContainerName(container)).setContainerImage(getContainerTag(container)) .setContainerImageTag(getContainerVersion(container)).setContainerID(container.getId()) .setContainerPorts(parseContainerPortsList(container.getPorts())) .setContainerState(convertDockerStateToFrameworkState(container.getState())) .setFrameworkManaged(isFrameworkManaged(container)).build())); return result; } private Boolean isFrameworkManaged(Container container) { String containerName = getContainerName(container); return this.frameworkManagedContainers.stream().anyMatch(c -> c.name.equals(containerName)); } private String getContainerName(Container container) { return container.getNames()[0].replace("/", ""); } private String getContainerVersion(Container container) { String version = ""; String[] image = container.getImage().split(":"); if (image.length > 1 && !image[0].startsWith("sha256")) { version = image[1]; } return version; } private String getContainerTag(Container container) { String[] image = container.getImage().split(":"); if (image[0].startsWith("sha256")) { return "none"; } else { return image[0]; } } private List parseContainerPortsList( ContainerPort[] ports) { List kuraContainerPorts = new ArrayList<>(); Arrays.asList(ports).stream().forEach(containerPort -> { String ipTest = containerPort.getIp(); if (ipTest != null && (ipTest.equals("::") || ipTest.equals("0.0.0.0"))) { kuraContainerPorts .add(new org.eclipse.kura.container.orchestration.ContainerPort(containerPort.getPrivatePort(), containerPort.getPublicPort(), parsePortInternetProtocol(containerPort.getType()))); } }); return kuraContainerPorts; } private PortInternetProtocol parsePortInternetProtocol(String dockerPortProtocol) { switch (dockerPortProtocol) { case "tcp": return PortInternetProtocol.TCP; case "udp": return PortInternetProtocol.UDP; case "sctp": return PortInternetProtocol.SCTP; default: throw new IllegalStateException(); } } private ContainerState convertDockerStateToFrameworkState(String dockerState) { switch (dockerState.trim()) { case "created": return ContainerState.INSTALLED; case "restarting": return ContainerState.INSTALLED; case "running": return ContainerState.ACTIVE; case "paused": return ContainerState.STOPPING; case "exited": return ContainerState.STOPPING; case "dead": return ContainerState.FAILED; default: return ContainerState.INSTALLED; } } @Override public Optional getContainerIdByName(String name) { checkRequestEnv(name); List containers = this.dockerClient.listContainersCmd().withShowAll(true).exec(); for (Container cont : containers) { String[] containerNames = cont.getNames(); for (String containerName : containerNames) { if (containerName.equals("/" + name)) { // docker API seems to put a '/' in front of the names return Optional.of(cont.getId()); } } } return Optional.empty(); } @Override public void startContainer(String id) throws KuraException { checkRequestEnv(id); try { this.dockerClient.startContainerCmd(id).exec(); } catch (Exception e) { logger.error("Could not start container {}. It could be already running or not exist at all. Caused by {}", id, e); throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR); } } @Override public String startContainer(ContainerConfiguration container) throws KuraException, InterruptedException { checkRequestEnv(container); logger.info("Starting {} Microservice", container.getContainerName()); final Optional existingInstance = listContainerDescriptors().stream() .filter(c -> c.getContainerName().equals(container.getContainerName())).findAny(); String containerId; if (existingInstance.isPresent()) { if (existingInstance.get().getContainerState() == ContainerState.ACTIVE) { logger.info("Found already existing running container"); containerId = existingInstance.get().getContainerId(); } else { logger.info("Found already exisiting not running container, recreating it.."); containerId = existingInstance.get().getContainerId(); deleteContainer(containerId); pullImage(container.getImageConfiguration()); containerId = createContainer(container); startContainer(containerId); } } else { logger.info("Creating new container instance"); pullImage(container.getImageConfiguration()); containerId = createContainer(container); addContainerInstanceDigest(containerId, container.getEnforcementDigest()); startContainer(containerId); } logger.info("Container Started Successfully"); if (container.isFrameworkManaged()) { this.frameworkManagedContainers .add(new FrameworkManagedContainer(container.getContainerName(), containerId)); } return containerId; } @Override public void stopContainer(String id) throws KuraException { checkRequestEnv(id); try { if (listContainersIds().contains(id)) { this.dockerClient.stopContainerCmd(id).exec(); } } catch (NotModifiedException e) { logger.debug("Container {} already stopped", id); } catch (Exception e) { logger.error("Could not stop container {}. Caused by {}", id, e); throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR); } } @Override public void deleteContainer(String id) throws KuraException { checkRequestEnv(id); try { if (listContainersIds().contains(id)) { this.dockerClient.removeContainerCmd(id).exec(); } this.frameworkManagedContainers.removeIf(c -> id.equals(c.id)); removeContainerInstanceDigest(id); } catch (Exception e) { logger.error("Could not remove container {}. Caused by {}", id, e); throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR); } } private void checkRequestEnv(Object parameter) { if (isNull(parameter)) { throw new IllegalArgumentException(PARAMETER_CANNOT_BE_NULL); } if (!testConnection()) { throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI); } } @Override public void registerListener(ContainerOrchestrationServiceListener dockerListener) { this.dockerServiceListeners.add(dockerListener); } @Override public void unregisterListener(ContainerOrchestrationServiceListener dockerListener) { this.dockerServiceListeners.remove(dockerListener); } private void imagePullHelper(String imageName, String imageTag, int timeOutSeconds, Optional repositoryCredentials) throws InterruptedException, KuraException { logger.info("Attempting to pull image: {}.", imageName); PullImageCmd pullRequest = this.dockerClient.pullImageCmd(imageName).withTag(imageTag); if (repositoryCredentials.isPresent()) { doAuthenticate(repositoryCredentials.get(), pullRequest); } pullRequest.exec(new PullImageResultCallback() { @Override public void onNext(PullResponseItem item) { super.onNext(item); createLoggerMessageForContainerPull(item, imageName, imageTag); } }).awaitCompletion(timeOutSeconds, TimeUnit.SECONDS); } private void doAuthenticate(RegistryCredentials repositoryCredentials, PullImageCmd pullRequest) throws KuraException { if (!(repositoryCredentials instanceof PasswordRegistryCredentials)) { throw new KuraException(KuraErrorCode.BAD_REQUEST); } PasswordRegistryCredentials repositoryPasswordCredentials = (PasswordRegistryCredentials) repositoryCredentials; AuthConfig authConfig = new AuthConfig().withUsername(repositoryPasswordCredentials.getUsername()).withPassword( new String(this.cryptoService.decryptAes(repositoryPasswordCredentials.getPassword().getPassword()))); Optional url = repositoryPasswordCredentials.getUrl(); if (url.isPresent()) { logger.info("Attempting to sign into repo: {}", url.get()); authConfig = authConfig.withRegistryAddress(url.get()); } pullRequest.withAuthConfig(authConfig); } private void createLoggerMessageForContainerPull(PullResponseItem item, String imageName, String imageTag) { if (logger.isDebugEnabled()) { logger.debug("Pulling {}:{} Layer {}, State: {}", imageName, imageTag, item.getId(), item.getStatus()); } if (item.isErrorIndicated()) { logger.error("Unable To Pull image {}:{} because : {}", item.getErrorDetail(), imageName, imageTag); } if (item.isPullSuccessIndicated()) { logger.info("Image pull of {}:{}, Layer: {}, was successful", imageName, imageTag, item.getId()); } } private String createContainer(ContainerConfiguration containerDescription) throws KuraException { if (!testConnection()) { throw new IllegalStateException("failed to reach docker engine"); } if (containerDescription == null) { throw new IllegalStateException("failed to create container, null containerImage passed"); } String containerImageFullString = String.format("%s:%s", containerDescription.getImageConfiguration().getImageName(), containerDescription.getImageConfiguration().getImageTag()); CreateContainerCmd commandBuilder = null; try { commandBuilder = this.dockerClient.createContainerCmd(containerImageFullString); if (containerDescription.getContainerName() != null) { commandBuilder = commandBuilder.withName(containerDescription.getContainerName()); } HostConfig configuration = new HostConfig(); commandBuilder = containerEnviromentVariablesHandler(containerDescription, commandBuilder); commandBuilder = containerEntrypointHandler(containerDescription, commandBuilder); // Host Configuration Related configuration = containerVolumeMangamentHandler(containerDescription, configuration); configuration = containerDevicesHandler(containerDescription, configuration); if (containerDescription.getRestartOnFailure()) { configuration = configuration.withRestartPolicy(RestartPolicy.unlessStoppedRestart()); } configuration = containerPortManagementHandler(containerDescription, configuration, commandBuilder); configuration = containerLogConfigurationHandler(containerDescription, configuration); configuration = containerNetworkConfigurationHandler(containerDescription, configuration); configuration = containerMemoryConfigurationHandler(containerDescription, configuration); configuration = containerCpusConfigurationHandler(containerDescription, configuration); configuration = containerGpusConfigurationHandler(containerDescription, configuration); configuration = containerRuntimeConfigurationHandler(containerDescription, configuration); if (containerDescription.isContainerPrivileged()) { configuration = configuration.withPrivileged(containerDescription.isContainerPrivileged()); } return commandBuilder.withHostConfig(configuration).exec().getId(); } catch (Exception e) { logger.error("Failed to create container", e); throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR); } finally { if (!isNull(commandBuilder)) { commandBuilder.close(); } } } private HostConfig containerLogConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { LoggingType lt; switch (containerDescription.getContainerLoggingType().toUpperCase().trim()) { case "NONE": lt = LoggingType.NONE; break; case "LOCAL": lt = LoggingType.LOCAL; break; case "ETWLOGS": lt = LoggingType.ETWLOGS; break; case "JSON_FILE": lt = LoggingType.JSON_FILE; break; case "SYSLOG": lt = LoggingType.SYSLOG; break; case "JOURNALD": lt = LoggingType.JOURNALD; break; case "GELF": lt = LoggingType.GELF; break; case "FLUENTD": lt = LoggingType.FLUENTD; break; case "AWSLOGS": lt = LoggingType.AWSLOGS; break; case "DB": lt = LoggingType.DB; break; case "SPLUNK": lt = LoggingType.SPLUNK; break; case "GCPLOGS": lt = LoggingType.GCPLOGS; break; case "LOKI": lt = LoggingType.LOKI; break; default: lt = LoggingType.DEFAULT; break; } LogConfig lc = new LogConfig(lt, containerDescription.getLoggerParameters()); configuration.withLogConfig(lc); return configuration; } private HostConfig containerNetworkConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { Optional networkMode = containerDescription.getContainerNetworkConfiguration().getNetworkMode(); if (networkMode.isPresent() && !networkMode.get().trim().isEmpty()) { configuration.withNetworkMode(networkMode.get().trim()); } return configuration; } private HostConfig containerMemoryConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { Optional memory = containerDescription.getMemory(); if (memory.isPresent()) { try { configuration.withMemory(memory.get()); } catch (NumberFormatException e) { logger.warn("Memory value {} not valid. Caused by {}", memory.get(), e); } } return configuration; } private HostConfig containerCpusConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { Optional cpus = containerDescription.getCpus(); cpus.ifPresent(cpu -> { configuration.withCpuPeriod(100000L); configuration.withCpuQuota((long) (100000L * cpus.get())); }); return configuration; } private HostConfig containerGpusConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { Optional gpus = containerDescription.getGpus(); gpus.ifPresent(gpu -> configuration.withDeviceRequests(ImmutableList .of(new DeviceRequest().withDriver("nvidia").withCount(gpu.equals("all") ? -1 : Integer.parseInt(gpu)) .withCapabilities(ImmutableList.of(ImmutableList.of("gpu")))))); return configuration; } private HostConfig containerRuntimeConfigurationHandler(ContainerConfiguration containerDescription, HostConfig configuration) { Optional runtime = containerDescription.getRuntime(); runtime.ifPresent(configuration::withRuntime); return configuration; } private HostConfig containerPortManagementHandler(ContainerConfiguration containerConfiguration, HostConfig hostConfig, CreateContainerCmd commandBuilder) { List exposedPorts = new LinkedList<>(); Ports portbindings = new Ports(); if (containerConfiguration.getContainerPorts() != null && !containerConfiguration.getContainerPorts().isEmpty()) { List containerPorts = containerConfiguration .getContainerPorts(); for (org.eclipse.kura.container.orchestration.ContainerPort port : containerPorts) { InternetProtocol ipProtocol = InternetProtocol.TCP; if (port.getInternetProtocol() != null) { try { ipProtocol = InternetProtocol.parse(port.getInternetProtocol().toString()); } catch (IllegalArgumentException e) { logger.warn("Invalid internet protocol: {}. Using TCP.", port.getInternetProtocol()); } } ExposedPort exposedPort = new ExposedPort(port.getInternalPort(), ipProtocol); exposedPorts.add(exposedPort); portbindings.bind(exposedPort, Binding.bindPort(port.getExternalPort())); } if (exposedPorts.size() != portbindings.getBindings().size()) { logger.error("portsExternal and portsInternal must have the same size: {}", containerConfiguration.getContainerName()); } } hostConfig.withPortBindings(portbindings); commandBuilder.withExposedPorts(exposedPorts); return hostConfig; } private CreateContainerCmd containerEnviromentVariablesHandler(ContainerConfiguration containerDescription, CreateContainerCmd commandBuilder) { if (containerDescription.getContainerEnvVars().isEmpty()) { return commandBuilder; } if (containerDescription.getContainerEnvVars() != null && !containerDescription.getContainerEnvVars().isEmpty()) { List formattedEnvVars = new LinkedList<>(); for (String env : containerDescription.getContainerEnvVars()) { if (!env.trim().isEmpty()) { formattedEnvVars.add(env.trim()); } } commandBuilder = commandBuilder.withEnv(formattedEnvVars); } return commandBuilder; } private CreateContainerCmd containerEntrypointHandler(ContainerConfiguration containerDescription, CreateContainerCmd commandBuilder) { if (containerDescription.getEntryPoint().isEmpty() || containerDescription.getEntryPoint() == null) { return commandBuilder; } return commandBuilder.withEntrypoint(containerDescription.getEntryPoint()); } private HostConfig containerVolumeMangamentHandler(ContainerConfiguration containerDescription, HostConfig hostConfiguration) { if (containerDescription.getContainerVolumes().isEmpty()) { return hostConfiguration; } List bindsToAdd = new LinkedList<>(); if (containerDescription.getContainerVolumes() != null && !containerDescription.getContainerVolumes().isEmpty()) { for (Map.Entry element : containerDescription.getContainerVolumes().entrySet()) { // source: path on host (key) // destination: path in container (value) if (!element.getKey().isEmpty() && !element.getValue().isEmpty()) { Volume tempVolume = new Volume(element.getValue()); Bind tempBind = new Bind(element.getKey(), tempVolume); bindsToAdd.add(tempBind); } } hostConfiguration = hostConfiguration.withBinds(bindsToAdd); } return hostConfiguration; } private HostConfig containerDevicesHandler(ContainerConfiguration containerDescription, HostConfig hostConfiguration) { if (containerDescription.getContainerDevices().isEmpty()) { return hostConfiguration; } if (containerDescription.getContainerDevices() != null && !containerDescription.getContainerDevices().isEmpty()) { List deviceList = new LinkedList<>(); for (String deviceString : containerDescription.getContainerDevices()) { deviceList.add(Device.parse(deviceString)); } if (!deviceList.isEmpty()) { hostConfiguration = hostConfiguration.withDevices(deviceList); } } return hostConfiguration; } private boolean doesImageExist(String imageName, String imageTag) { if (!testConnection()) { throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI); } List images = this.dockerClient.listImagesCmd().exec(); String requiredImage = imageName + ":" + imageTag; for (Image image : images) { if (isNull(image.getRepoTags())) { continue; } for (String tag : image.getRepoTags()) { if (tag.equals(requiredImage)) { return true; } } } return false; } private void cleanUpDocker() { if (this.allowlistEnforcementMonitor != null) { closeEnforcementMonitor(); } if (testConnection()) { this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onDisabled); disconnect(); } } private boolean connect() { if (this.currentConfig.getHostUrl() == null) { return false; } DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withDockerHost(this.currentConfig.getHostUrl()).build(); DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder().dockerHost(config.getDockerHost()).build(); this.dockerClient = DockerClientImpl.getInstance(config, httpClient); final boolean connected = testConnection(); if (connected) { this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onConnect); } return connected; } private void disconnect() { if (testConnection()) { try { this.dockerServiceListeners.forEach(ContainerOrchestrationServiceListener::onDisconnect); this.dockerClient.close(); } catch (IOException e) { logger.error("Error disconnecting", e); } } } private boolean testConnection() { boolean canConnect = false; try { this.dockerClient.pingCmd().exec(); canConnect = true; } catch (Exception ex) { canConnect = false; } return canConnect; } private static class FrameworkManagedContainer { private final String name; private final String id; public FrameworkManagedContainer(String name, String id) { this.name = name; this.id = id; } @Override public int hashCode() { return Objects.hash(this.id, this.name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } FrameworkManagedContainer other = (FrameworkManagedContainer) obj; return Objects.equals(this.id, other.id) && Objects.equals(this.name, other.name); } } @Override public void pullImage(ImageConfiguration imageConfig) throws KuraException, InterruptedException { if (isNull(imageConfig.getImageName()) || isNull(imageConfig.getImageTag()) || imageConfig.getimageDownloadTimeoutSeconds() < 0 || isNull(imageConfig.getRegistryCredentials())) { throw new IllegalArgumentException("Parameters cannot be null or negative"); } boolean imageAvailableLocally = doesImageExist(imageConfig.getImageName(), imageConfig.getImageTag()); if (!imageAvailableLocally) { try { imagePullHelper(imageConfig.getImageName(), imageConfig.getImageTag(), imageConfig.getimageDownloadTimeoutSeconds(), imageConfig.getRegistryCredentials()); } catch (InterruptedException e) { throw e; } catch (Exception e) { logger.error("Cannot pull container. Caused by ", e); throw new KuraException(KuraErrorCode.IO_ERROR, "Unable to pull container"); } } } @Override public void pullImage(String imageName, String imageTag, int timeOutSeconds, Optional registryCredentials) throws KuraException, InterruptedException { pullImage(new ImageConfiguration.ImageConfigurationBuilder().setImageName(imageName).setImageTag(imageTag) .setImageDownloadTimeoutSeconds(timeOutSeconds).setRegistryCredentials(registryCredentials).build()); } @Override public List listImageInstanceDescriptors() { if (!testConnection()) { throw new IllegalStateException(UNABLE_TO_CONNECT_TO_DOCKER_CLI); } List images = this.dockerClient.listImagesCmd().withShowAll(true).exec(); List result = new ArrayList<>(); images.forEach(image -> { InspectImageResponse iir = this.dockerClient.inspectImageCmd(image.getId()).exec(); ImageInstanceDescriptorBuilder imageBuilder = ImageInstanceDescriptor.builder() .setImageName(getImageName(image)).setImageTag(getImageTag(image)).setImageId(image.getId()) .setImageAuthor(iir.getAuthor()).setImageArch(iir.getArch()) .setimageSize(iir.getSize().longValue()); if (image.getLabels() != null) { imageBuilder.setImageLabels(image.getLabels()); } result.add(imageBuilder.build()); }); return result; } private String getImageName(Image image) { if (image.getRepoTags() == null || image.getRepoTags().length < 1) { return ""; } return image.getRepoTags()[0].split(":")[0]; } private String getImageTag(Image image) { if (image.getRepoTags() == null || image.getRepoTags().length < 1 || image.getRepoTags()[0].split(":").length < 2) { return ""; } return image.getRepoTags()[0].split(":")[1]; } @Override public void deleteImage(String imageId) throws KuraException { checkRequestEnv(imageId); try { this.dockerClient.removeImageCmd(imageId).exec(); } catch (Exception e) { logger.error("Could not remove image {}. Caused by {}", imageId, e); throw new KuraException(KuraErrorCode.OS_COMMAND_ERROR, "Delete Container Image", "500 (server error). Image is most likely in use by a container."); } } public Set getImageDigestsByContainerId(String containerId) { Set imageDigests = new HashSet<>(); String containerName = listContainerDescriptors().stream() .filter(container -> container.getContainerId().equals(containerId)).findFirst() .map(container -> container.getContainerName()).orElse(null); if (containerName == null) { return imageDigests; } dockerClient.listImagesCmd().withImageNameFilter(containerName).exec().stream().forEach(image -> { List digests = Arrays.asList(image.getRepoDigests()); digests.stream().forEach(digest -> imageDigests.add(digest.split("@")[1])); }); return imageDigests; } private void addContainerInstanceDigest(String containerId, Optional containerInstanceDigest) { if (containerInstanceDigest.isPresent()) { logger.info( "Container {} presented enforcement digest. Adding it to the digests allowlist: it will be used if the enforcement is enabled.", containerId); this.containerInstancesDigests.put(containerId, containerInstanceDigest.get()); } else { logger.info("Container {} doesn't contain the enforcement digest. " + "If enforcement is enabled, be sure that the digest is included in the Orchestration Service allowlist", containerId); } } private void removeContainerInstanceDigest(String containerId) { if (this.containerInstancesDigests.containsKey(containerId)) { this.containerInstancesDigests.remove(containerId); logger.info("Removed digest of container with ID {} from Container Instances Allowlist", containerId); enforceAlreadyRunningContainer(); } } public Set getContainerInstancesAllowlist() { return new HashSet<>(this.containerInstancesDigests.values()); } } ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/ContainerOrchestrationServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration.provider.impl; import static java.util.Objects.isNull; import java.util.Map; import java.util.Objects; import org.eclipse.kura.util.configuration.Property; public class ContainerOrchestrationServiceOptions { private static final Property IS_ENABLED = new Property<>("enabled", false); private static final Property DOCKER_HOST_URL = new Property<>("container.engine.host", "unix:///var/run/docker.sock"); private static final Property ENFORCEMENT_ENABLED = new Property<>("enforcement.enabled", false); private static final Property ENFORCEMENT_ALLOWLIST = new Property<>("enforcement.allowlist", ""); private final boolean enabled; private final String hostUrl; private final boolean enforcementEnabled; private final String enforcementAllowlist; public ContainerOrchestrationServiceOptions(final Map properties) { if (isNull(properties)) { throw new IllegalArgumentException("Properties cannot be null!"); } this.enabled = IS_ENABLED.get(properties); this.hostUrl = DOCKER_HOST_URL.get(properties); this.enforcementEnabled = ENFORCEMENT_ENABLED.get(properties); this.enforcementAllowlist = ENFORCEMENT_ALLOWLIST.get(properties); } public boolean isEnabled() { return this.enabled; } public String getHostUrl() { return this.hostUrl; } public boolean isEnforcementEnabled() { return this.enforcementEnabled; } public String getEnforcementAllowlist() { return this.enforcementAllowlist; } @Override public int hashCode() { return Objects.hash(enforcementAllowlist, enforcementEnabled, enabled, hostUrl); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ContainerOrchestrationServiceOptions other = (ContainerOrchestrationServiceOptions) obj; return Objects.equals(enforcementAllowlist, other.enforcementAllowlist) && enforcementEnabled == other.enforcementEnabled && enabled == other.enabled && Objects.equals(hostUrl, other.hostUrl); } } ================================================ FILE: kura/org.eclipse.kura.container.orchestration.provider/src/main/java/org/eclipse/kura/container/orchestration/provider/impl/enforcement/AllowlistEnforcementMonitor.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.container.orchestration.provider.impl.enforcement; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.kura.KuraException; import org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor; import org.eclipse.kura.container.orchestration.ContainerState; import org.eclipse.kura.container.orchestration.provider.impl.ContainerOrchestrationServiceImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.github.dockerjava.api.async.ResultCallbackTemplate; import com.github.dockerjava.api.model.Event; public class AllowlistEnforcementMonitor extends ResultCallbackTemplate { private static final Logger logger = LoggerFactory.getLogger(AllowlistEnforcementMonitor.class); private static final String ENFORCEMENT_CHECK_SUCCESS = "Enforcement allowlist contains image digests {}...container {} is starting"; private static final String ENFORCEMENT_CHECK_FAILURE = "Enforcement allowlist doesn't contain image digests...container {} will be stopped"; private final Set enforcementAllowlistContent; private final ContainerOrchestrationServiceImpl orchestrationServiceImpl; public AllowlistEnforcementMonitor(String allowlistContent, ContainerOrchestrationServiceImpl containerOrchestrationService) { this.enforcementAllowlistContent = Arrays.asList(allowlistContent.replace(" ", "").split("\\r?\\n|\\r")) .stream().filter(line -> !line.isEmpty()).collect(Collectors.toSet()); this.orchestrationServiceImpl = containerOrchestrationService; } @Override public void onNext(Event item) { enforceAllowlistFor(item.getId()); } private void enforceAllowlistFor(String containerId) { Set digestsList = this.orchestrationServiceImpl.getImageDigestsByContainerId(containerId); Set digestIntersection = this.enforcementAllowlistContent.stream().distinct() .filter(digestsList::contains).collect(Collectors.toSet()); if (digestIntersection.isEmpty()) { digestIntersection = this.orchestrationServiceImpl.getContainerInstancesAllowlist().stream().distinct() .filter(digestsList::contains).collect(Collectors.toSet()); } if (!digestIntersection.isEmpty()) { logger.info(ENFORCEMENT_CHECK_SUCCESS, digestIntersection, containerId); } else { logger.info(ENFORCEMENT_CHECK_FAILURE, containerId); stopContainer(containerId); deleteContainer(containerId); } } public void enforceAllowlistFor(List containerDescriptors) { for (ContainerInstanceDescriptor descriptor : containerDescriptors) { enforceAllowlistFor(descriptor.getContainerId()); } } private void stopContainer(String containerId) { this.orchestrationServiceImpl.listContainerDescriptors().stream() .filter(descriptor -> descriptor.getContainerId().equals(containerId)).findFirst() .ifPresent(descriptor -> { if (descriptor.getContainerState().equals(ContainerState.ACTIVE) || descriptor.getContainerState().equals(ContainerState.STARTING)) { try { this.orchestrationServiceImpl.stopContainer(descriptor.getContainerId()); } catch (KuraException ex) { logger.error("Error during container stopping process of {}:", descriptor.getContainerId(), ex); } } }); } private void deleteContainer(String containerId) { try { this.orchestrationServiceImpl.deleteContainer(containerId); } catch (KuraException ex) { logger.error("Error during container deleting process of {}:", containerId, ex); } } } ================================================ FILE: kura/org.eclipse.kura.container.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Configurable custom container service Bundle-SymbolicName: org.eclipse.kura.container.provider;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: EUROTECH Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: org.eclipse.kura;version="[1.3,2.0)", org.eclipse.kura.configuration;version="[1.2,1.3)", org.eclipse.kura.container.orchestration;version="[1.2,2.0)", org.eclipse.kura.container.orchestration.listener;version="[1.0,1.1)", org.eclipse.kura.container.signature;version="[1.0,2.0)", org.eclipse.kura.crypto;version="[1.3,2.0)", org.eclipse.kura.identity;version="[1.2,2.0)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.util.configuration;version="[1.0,2.0)", org.osgi.service.component;version="1.4.0", org.slf4j;version="1.7.25" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy ================================================ FILE: kura/org.eclipse.kura.container.provider/OSGI-INF/containerinstance.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.container.provider/OSGI-INF/metatype/org.eclipse.kura.container.provider.ContainerInstance.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.container.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.container.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.container.provider/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/ source.. = src/main/java/ ================================================ FILE: kura/org.eclipse.kura.container.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.container.provider 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml org.eclipse.tycho tycho-packaging-plugin ${tycho-version} org.apache.maven.plugins maven-jarsigner-plugin 1.4 de.dentrassi.maven osgi-dp 0.4.1 build org.eclipse.m2e lifecycle-mapping 1.0.0 org.codehaus.mojo properties-maven-plugin [1.0-alpha-1,) read-project-properties org.codehaus.mojo build-helper-maven-plugin [1.9,) regex-property ================================================ FILE: kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/ContainerInstance.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.container.provider; import static java.util.Objects.isNull; import java.net.Inet4Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; import java.util.stream.Collectors; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.container.orchestration.ContainerConfiguration; import org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor; import org.eclipse.kura.container.orchestration.ContainerOrchestrationService; import org.eclipse.kura.container.orchestration.RegistryCredentials; import org.eclipse.kura.container.orchestration.listener.ContainerOrchestrationServiceListener; import org.eclipse.kura.container.signature.ContainerSignatureValidationService; import org.eclipse.kura.container.signature.ValidationResult; import org.eclipse.kura.identity.AssignedPermissions; import org.eclipse.kura.identity.IdentityConfiguration; import org.eclipse.kura.identity.IdentityService; import org.eclipse.kura.identity.PasswordConfiguration; import org.eclipse.kura.identity.PasswordStrengthVerificationService; import org.eclipse.kura.identity.Permission; import org.eclipse.kura.net.IP4Address; import org.eclipse.kura.net.IPAddress; import org.eclipse.kura.net.NetInterface; import org.eclipse.kura.net.NetInterfaceAddress; import org.eclipse.kura.net.NetworkService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ContainerInstance implements ConfigurableComponent, ContainerOrchestrationServiceListener { private static final Logger logger = LoggerFactory.getLogger(ContainerInstance.class); private static final ValidationResult FAILED_VALIDATION = new ValidationResult(); private static final String CONTAINER_IDENTITY_PREFIX = "container_"; private static final int MAX_IDENTITY_NAME_LENGTH = 255; private static final int MAX_IDENTITY_NAME_GENERATION_ATTEMPTS = 10; private final ExecutorService executor = Executors.newSingleThreadExecutor(); private ContainerOrchestrationService containerOrchestrationService; private Set availableContainerSignatureValidationService = new HashSet<>(); private ConfigurationService configurationService; private IdentityService identityService; private NetworkService networkService; private PasswordStrengthVerificationService passwordStrengthVerificationService; private State state = new Disabled(new ContainerInstanceOptions(Collections.emptyMap())); private ContainerInstanceOptions currentOptions = null; private final AtomicReference currentTemporaryIdentityName = new AtomicReference<>(); private final AtomicReference currentTemporaryPassword = new AtomicReference<>(); public void setContainerOrchestrationService(final ContainerOrchestrationService containerOrchestrationService) { this.containerOrchestrationService = containerOrchestrationService; } public void setPasswordStrengthVerificationService( final PasswordStrengthVerificationService passwordStrengthVerificationService) { this.passwordStrengthVerificationService = passwordStrengthVerificationService; } public synchronized void setContainerSignatureValidationService( final ContainerSignatureValidationService containerSignatureValidationService) { logger.info("Container signature validation service {} added.", containerSignatureValidationService.getClass()); this.availableContainerSignatureValidationService.add(containerSignatureValidationService); } public synchronized void unsetContainerSignatureValidationService( final ContainerSignatureValidationService containerSignatureValidationService) { logger.info("Container signature validation service {} removed.", containerSignatureValidationService.getClass()); this.availableContainerSignatureValidationService.remove(containerSignatureValidationService); } public synchronized void setConfigurationService(final ConfigurationService confService) { this.configurationService = confService; } public synchronized void setIdentityService(final IdentityService identityService) { this.identityService = identityService; } public synchronized void setNetworkService(final NetworkService networkService) { this.networkService = networkService; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- public void activate(final Map properties) { logger.info("activating..."); updated(properties); logger.info("activating...done"); } public void updated(Map properties) { if (isNull(properties)) { throw new IllegalArgumentException("Properties cannot be null!"); } try { ContainerInstanceOptions newOptions = new ContainerInstanceOptions(properties); if (this.currentOptions != null && this.currentOptions.equals(newOptions)) { return; } this.currentOptions = newOptions; if (!this.currentOptions.getEnforcementDigest().isPresent()) { logger.info( "Container configuration doesn't include enforcement digest. Validating with Container Signature Validation service"); if (this.currentOptions.getSignatureTrustAnchor().isPresent()) { ValidationResult containerSignatureValidated = validateContainerImageSignature(this.currentOptions); logger.info("Container signature validation result for {}@{}({}) - {}", this.currentOptions.getContainerImage(), containerSignatureValidated.imageDigest().orElse("?"), this.currentOptions.getContainerImageTag(), containerSignatureValidated.isSignatureValid() ? "OK" : "FAIL"); containerSignatureValidated.imageDigest().ifPresent(digest -> { Map updatedProperties = updatePropertiesWithSignatureDigest(properties, digest); this.currentOptions = new ContainerInstanceOptions(updatedProperties); updateSnapshotWithSignatureDigest(updatedProperties); }); } else { logger.info("No trust anchor available. Signature validation skipped."); } } if (this.currentOptions.isEnabled()) { this.containerOrchestrationService.registerListener(this); } else { this.containerOrchestrationService.unregisterListener(this); } updateState(s -> s.onConfigurationUpdated(this.currentOptions)); } catch (Exception e) { logger.error("Failed to create container instance. Please check configuration of container: {}. Caused by:", properties.get(ConfigurationService.KURA_SERVICE_PID), e); updateState(State::onDisabled); } } public void deactivate() { logger.info("deactivate..."); updateState(State::onDisabled); cleanupTemporaryIdentity(); this.executor.shutdown(); this.containerOrchestrationService.unregisterListener(this); logger.info("deactivate...done"); } public synchronized String getState() { return this.state.getClass().getSimpleName(); } // ---------------------------------------------------------------- // // Private methods // // ---------------------------------------------------------------- @Override public void onConnect() { updateState(State::onConnect); } @Override public void onDisconnect() { // } @Override public void onDisabled() { updateState(State::onDisabled); } private ValidationResult validateContainerImageSignature(ContainerInstanceOptions configuration) { if (Objects.isNull(this.availableContainerSignatureValidationService) || this.availableContainerSignatureValidationService.isEmpty()) { logger.warn("No container signature validation service available. Signature validation failed."); return FAILED_VALIDATION; } Optional optTrustAnchor = configuration.getSignatureTrustAnchor(); if (!optTrustAnchor.isPresent() || optTrustAnchor.get().isEmpty()) { logger.warn("No trust anchor available. Signature validation failed."); return FAILED_VALIDATION; } String trustAnchor = optTrustAnchor.get(); boolean verifyInTransparencyLog = configuration.getSignatureVerifyTransparencyLog(); Optional registryCredentials = configuration.getRegistryCredentials(); for (ContainerSignatureValidationService validationService : this.availableContainerSignatureValidationService) { ValidationResult results = FAILED_VALIDATION; try { if (registryCredentials.isPresent()) { results = validationService.verify(configuration.getContainerImage(), configuration.getContainerImageTag(), trustAnchor, verifyInTransparencyLog, registryCredentials.get()); } else { results = validationService.verify(configuration.getContainerImage(), configuration.getContainerImageTag(), trustAnchor, verifyInTransparencyLog); } } catch (KuraException e) { logger.warn( "Error validating container signature with {}. Setting validation results as FAILED. Caused by: ", validationService.getClass(), e); } if (results.isSignatureValid()) { return results; } } return FAILED_VALIDATION; } private synchronized void updateState(final UnaryOperator update) { final State previous = this.state; final State newState = update.apply(previous); logger.info("State update: {} -> {}", previous.getClass().getSimpleName(), newState.getClass().getSimpleName()); this.state = newState; } private Optional getExistingContainerByName(final String containerName) { return containerOrchestrationService.listContainerDescriptors().stream() .filter(c -> c.getContainerName().equals(containerName)).findAny(); } private interface State { public default State onConnect() { return this; } public default State onConfigurationUpdated(final ContainerInstanceOptions options) { return this; } public default State onContainerReady(final String containerId) { return this; } public default State onStartupFailure() { return this; } public default State onDisabled() { return this; } } private class Disabled implements State { private final ContainerInstanceOptions options; public Disabled(ContainerInstanceOptions options) { this.options = options; } @Override public State onConfigurationUpdated(ContainerInstanceOptions options) { return updateStateInternal(options); } @Override public State onConnect() { return updateStateInternal(this.options); } private State updateStateInternal(ContainerInstanceOptions newOptions) { final Optional existingContainer; final boolean isInstanceEnabled = newOptions.isEnabled(); try { existingContainer = getExistingContainerByName( newOptions.getContainerConfiguration().getContainerName()); } catch (final Exception e) { logger.warn("failed to get existing container state", e); return new Disabled(newOptions); } if (existingContainer.isPresent()) { logger.info("found existing container with name {}", newOptions.getContainerConfiguration().getContainerName()); if (isInstanceEnabled) { return new Starting(newOptions); } else { return new Created(newOptions, existingContainer.get().getContainerId()).onDisabled(); } } else { if (isInstanceEnabled) { return new Starting(newOptions); } else { return new Disabled(newOptions); } } } } private class Starting implements State { private final ContainerInstanceOptions options; private final Future startupFuture; public Starting(final ContainerInstanceOptions options) { this.options = options; this.startupFuture = ContainerInstance.this.executor.submit(() -> startMicroservice(options)); } private ContainerConfiguration getContainerConfigurationWithCredentials( final ContainerInstanceOptions options) { ContainerConfiguration baseConfig = options.getContainerConfiguration(); final String identityName = ContainerInstance.this.currentTemporaryIdentityName.get(); final char[] password = ContainerInstance.this.currentTemporaryPassword.get(); if (options.isIdentityIntegrationEnabled() && password != null && identityName != null) { final List envVars = new ArrayList<>(baseConfig.getContainerEnvVars()); envVars.add("KURA_IDENTITY_NAME=" + identityName); envVars.add("KURA_IDENTITY_PASSWORD=" + new String(password)); String restBaseUrl = buildRestBaseUrl(options); envVars.add("KURA_REST_BASE_URL=" + restBaseUrl); logger.info("Setting container REST base URL to: {}", restBaseUrl); return ContainerConfiguration.builder().setContainerName(baseConfig.getContainerName()) .setImageConfiguration(baseConfig.getImageConfiguration()) .setContainerPorts(baseConfig.getContainerPorts()).setEnvVars(envVars) .setVolumes(baseConfig.getContainerVolumes()) .setPrivilegedMode(baseConfig.isContainerPrivileged()) .setDeviceList(baseConfig.getContainerDevices()) .setFrameworkManaged(baseConfig.isFrameworkManaged()) .setLoggingType(baseConfig.getContainerLoggingType()) .setContainerNetowrkConfiguration(baseConfig.getContainerNetworkConfiguration()) .setLoggerParameters(baseConfig.getLoggerParameters()).setEntryPoint(baseConfig.getEntryPoint()) .setRestartOnFailure(baseConfig.getRestartOnFailure()).setMemory(baseConfig.getMemory()) .setCpus(baseConfig.getCpus()).setGpus(baseConfig.getGpus()).setRuntime(baseConfig.getRuntime()) .setEnforcementDigest(baseConfig.getEnforcementDigest()).build(); } return baseConfig; } private void createTemporaryIdentityIfEnabled(final ContainerInstanceOptions options) { if (options.isIdentityIntegrationEnabled() && ContainerInstance.this.identityService != null) { try { cleanupTemporaryIdentity(); final Set permissions = options.getContainerPermissions().stream().map(Permission::new) .collect(Collectors.toSet()); // Generate password as char[] to minimize exposure final char[] password = PasswordGenerator .generatePassword(passwordStrengthVerificationService.getPasswordStrengthRequirements()); final String identityName = createTemporaryIdentityWithValidName(options, permissions, new String(password)); // Store identity name and a copy of the password for env injection ContainerInstance.this.currentTemporaryIdentityName.set(identityName); ContainerInstance.this.currentTemporaryPassword.set(Arrays.copyOf(password, password.length)); Arrays.fill(password, '\0'); logger.info("Created temporary identity {} for container {} with {} permissions", identityName, options.getContainerName(), permissions.size()); } catch (KuraException e) { logger.error("Failed to create temporary identity for container {}", options.getContainerName(), e); ContainerInstance.this.currentTemporaryIdentityName.set(null); clearTemporaryPassword(); } } } private String createTemporaryIdentityWithValidName(final ContainerInstanceOptions options, final Set permissions, final String password) throws KuraException { final String baseIdentityName = sanitizeContainerIdentityName(options.getContainerName()); for (int attempt = 0; attempt < MAX_IDENTITY_NAME_GENERATION_ATTEMPTS; attempt++) { final String candidateName = buildIdentityNameCandidate(baseIdentityName, attempt); try { final PasswordConfiguration passwordConfiguration = new PasswordConfiguration(false, true, Optional.of(password.toCharArray()), Optional.empty()); final AssignedPermissions assignedPermissions = new AssignedPermissions(permissions); final IdentityConfiguration configuration = new IdentityConfiguration(candidateName, Arrays.asList(passwordConfiguration, assignedPermissions)); ContainerInstance.this.identityService.createTemporaryIdentity(candidateName, Duration.ofDays(365)); ContainerInstance.this.identityService.updateIdentityConfiguration(configuration); return candidateName; } catch (final KuraException e) { if (!shouldRetryIdentityNameGeneration(e, attempt)) { throw e; } } } throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "Unable to generate a valid temporary identity name for container " + options.getContainerName()); } private String sanitizeContainerIdentityName(final String containerName) { String safeName = containerName.replaceAll("[^a-zA-Z0-9._]", "_"); safeName = safeName.replaceAll("[._]{2,}", "_"); safeName = trimIdentityDelimiters(safeName); if (safeName.isEmpty()) { safeName = "auto"; } return CONTAINER_IDENTITY_PREFIX + safeName; } private String trimIdentityDelimiters(final String value) { int start = 0; int end = value.length(); while (start < end && isIdentityDelimiter(value.charAt(start))) { start++; } while (end > start && isIdentityDelimiter(value.charAt(end - 1))) { end--; } return value.substring(start, end); } private boolean isIdentityDelimiter(final char value) { return value == '.' || value == '_'; } private String buildIdentityNameCandidate(final String baseIdentityName, final int attempt) { final String candidate = attempt == 0 ? baseIdentityName : baseIdentityName + "_" + attempt; if (candidate.length() <= MAX_IDENTITY_NAME_LENGTH) { return candidate; } if (attempt == 0) { return candidate.substring(0, MAX_IDENTITY_NAME_LENGTH); } final String suffix = "_" + attempt; return candidate.substring(0, MAX_IDENTITY_NAME_LENGTH - suffix.length()) + suffix; } private boolean shouldRetryIdentityNameGeneration(final KuraException e, final int attempt) { if (attempt == MAX_IDENTITY_NAME_GENERATION_ATTEMPTS - 1) { return false; } if (!KuraErrorCode.INVALID_PARAMETER.equals(e.getCode())) { return false; } final String message = e.getMessage(); return message != null && (message.contains("Identity name") || message.contains("identity with name") || message.contains("already exists")); } @Override public State onConfigurationUpdated(ContainerInstanceOptions newOptions) { if (newOptions.equals(this.options)) { return this; } cleanupTemporaryIdentity(); this.startupFuture.cancel(true); if (newOptions.isEnabled()) { return new Starting(newOptions); } else { return new Disabled(newOptions); } } @Override public State onContainerReady(final String containerId) { clearTemporaryPassword(); return new Created(this.options, containerId); } @Override public State onStartupFailure() { clearTemporaryPassword(); cleanupTemporaryIdentity(); return new Disabled(this.options); } @Override public State onDisabled() { this.startupFuture.cancel(true); try { final Optional existingInstance = getExistingContainerByName( this.options.getContainerName()); if (existingInstance.isPresent()) { return new Created(this.options, existingInstance.get().getContainerId()).onDisabled(); } } catch (final Exception e) { logger.warn("failed to check container state", e); } return new Disabled(this.options); } private void startMicroservice(final ContainerInstanceOptions options) { boolean unlimitedRetries = options.isUnlimitedRetries(); int maxRetries = options.getMaxDownloadRetries(); int retryInterval = options.getRetryInterval(); createTemporaryIdentityIfEnabled(options); final ContainerConfiguration containerConfiguration = getContainerConfigurationWithCredentials(options); int retries = 0; while ((unlimitedRetries || retries < maxRetries) && !Thread.currentThread().isInterrupted()) { try { logger.info("Tentative number: {}", retries); if (retries > 0) { Thread.sleep(retryInterval); } final String containerId = ContainerInstance.this.containerOrchestrationService .startContainer(containerConfiguration); updateState(s -> s.onContainerReady(containerId)); return; } catch (InterruptedException e) { logger.info("interrupted exiting"); Thread.currentThread().interrupt(); return; } catch (KuraException e) { logger.error("Error managing microservice state", e); if (!unlimitedRetries) { retries++; } } } updateState(State::onStartupFailure); logger.warn("Unable to start microservice...giving up"); } private String buildRestBaseUrl(ContainerInstanceOptions options) { boolean useHttps = isHttpsEnabled(); String protocol = useHttps ? "https" : "http"; String host = getHostAddressForNetworkMode(options.getContainerNetworkingMode().orElse("bridge")); String formattedHost = formatHostForUrl(host); int port = getRestServicePort(useHttps); return String.format("%s://%s:%d/services", protocol, formattedHost, port); } private String formatHostForUrl(String host) { if (host == null || host.isEmpty()) { return host; } if (host.startsWith("[") && host.endsWith("]")) { return host; } if (!host.contains(":")) { return host; } String encodedHost = host.contains("%25") ? host : host.replace("%", "%25"); return "[" + encodedHost + "]"; } private int getRestServicePort(boolean useHttps) { int defaultPort = useHttps ? 443 : 8080; if (ContainerInstance.this.configurationService == null) { logger.debug("ConfigurationService not available, using default port"); return defaultPort; } try { ComponentConfiguration config = ContainerInstance.this.configurationService .getComponentConfiguration("org.eclipse.kura.http.server.manager.HttpService"); return extractPortFromConfig(config, useHttps).orElse(defaultPort); } catch (KuraException e) { logger.warn("Failed to get REST service port configuration", e); } return defaultPort; } private Optional extractPortFromConfig(ComponentConfiguration config, boolean useHttps) { if (config == null || config.getConfigurationProperties() == null) { return Optional.empty(); } Map properties = config.getConfigurationProperties(); String portKey = useHttps ? "https.ports" : "http.ports"; Integer[] ports = (Integer[]) properties.get(portKey); if (ports != null && ports.length > 0) { return Optional.of(ports[0]); } return Optional.empty(); } private boolean isHttpsEnabled() { if (ContainerInstance.this.configurationService == null) { logger.debug("ConfigurationService not available, defaulting to HTTP"); return false; } try { ComponentConfiguration config = ContainerInstance.this.configurationService .getComponentConfiguration("org.eclipse.kura.http.server.manager.HttpService"); if (config != null && config.getConfigurationProperties() != null) { Map properties = config.getConfigurationProperties(); Integer[] httpsPorts = (Integer[]) properties.get("https.ports"); return httpsPorts != null && httpsPorts.length > 0; } } catch (KuraException e) { logger.warn("Failed to check HTTPS configuration", e); } return false; } private String getHostAddressForNetworkMode(String networkMode) { if ("host".equalsIgnoreCase(networkMode)) { logger.debug("Container using host network mode, using localhost"); return "localhost"; } return getAddressForBridgeMode(); } private String getAddressForBridgeMode() { String dockerGateway = getDockerBridgeGateway(); if (dockerGateway != null) { return dockerGateway; } String hostPrimaryIp = getHostPrimaryIpAddress(); if (hostPrimaryIp != null) { return hostPrimaryIp; } logger.warn("Could not determine host address, using host.docker.internal as fallback"); return "host.docker.internal"; } private String getDockerBridgeGateway() { String address = getDockerBridgeViaNetworkService(); if (address != null) { return address; } return getDockerBridgeViaJavaApi(); } private String getDockerBridgeViaNetworkService() { if (ContainerInstance.this.networkService == null) { return null; } try { for (NetInterface netInterface : ContainerInstance.this.networkService.getNetworkInterfaces()) { String address = extractDockerInterfaceAddress(netInterface); if (address != null) { return address; } } } catch (Exception e) { logger.debug("Failed to detect docker0 interface using NetworkService", e); } return null; } private String extractDockerInterfaceAddress(NetInterface netInterface) { if (!"docker0".equals(netInterface.getName())) { return null; } return getAddressNetworkService(netInterface.getNetInterfaceAddresses()); } private String getAddressNetworkService(List addresses) { if (addresses == null) { return null; } IPAddress candidate = null; for (final NetInterfaceAddress address : addresses) { candidate = address.getAddress(); if (candidate instanceof IP4Address) { break; } } return candidate != null ? candidate.getHostAddress() : null; } private String getDockerBridgeViaJavaApi() { try { NetworkInterface dockerInterface = NetworkInterface.getByName("docker0"); if (dockerInterface != null) { return getAddressJavaAPI(dockerInterface); } } catch (Exception e) { logger.debug("Failed to detect docker0 interface using Java NetworkInterface API", e); } return null; } private String getAddressJavaAPI(NetworkInterface nif) throws SocketException { final Enumeration addresses = nif.getInetAddresses(); InetAddress candidate = null; while (addresses.hasMoreElements()) { final InetAddress addr = addresses.nextElement(); if (!isValidAddress(addr, nif)) { continue; } candidate = addr; if (candidate instanceof Inet4Address) { break; } } return candidate != null ? candidate.getHostAddress() : null; } private String getHostPrimaryIpAddress() { try { Enumeration nifs = NetworkInterface.getNetworkInterfaces(); if (nifs != null) { return findSuitableNetworkAddress(nifs); } } catch (Exception e) { logger.warn("Failed to determine host IP address", e); } return null; } private String findSuitableNetworkAddress(Enumeration nifs) throws SocketException { while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); String address = getAddressFromInterface(nif); if (address != null) { return address; } } return null; } private String getAddressFromInterface(NetworkInterface nif) throws SocketException { if (!isValidNetworkInterface(nif)) { return null; } final String result = getAddressJavaAPI(nif); if (result != null) { logger.debug("Using host primary IP address: {}", result); } return result; } private boolean isValidNetworkInterface(NetworkInterface nif) throws SocketException { return !nif.isLoopback() && nif.isUp() && !nif.isVirtual() && nif.getHardwareAddress() != null; } private boolean isValidAddress(InetAddress adr, NetworkInterface nif) throws SocketException { return adr != null && !adr.isLoopbackAddress() && (nif.isPointToPoint() || !adr.isLinkLocalAddress()); } } private class Created implements State { private final ContainerInstanceOptions options; private final String containerId; public Created(ContainerInstanceOptions options, String containerId) { this.options = options; this.containerId = containerId; } private void deleteContainer() { try { ContainerInstance.this.containerOrchestrationService.stopContainer(this.containerId); } catch (Exception e) { logger.error("Error stopping microservice {}", this.options.getContainerName(), e); } try { ContainerInstance.this.containerOrchestrationService.deleteContainer(this.containerId); } catch (Exception e) { logger.error("Error deleting microservice {}", this.options.getContainerName(), e); } cleanupTemporaryIdentity(); } @Override public State onConfigurationUpdated(ContainerInstanceOptions options) { if (options.equals(this.options)) { return this; } deleteContainer(); if (options.isEnabled()) { return new Starting(options); } else { return new Disabled(options); } } @Override public State onDisabled() { deleteContainer(); return new Disabled(this.options); } } private Map updatePropertiesWithSignatureDigest(Map oldProperties, String enforcementDigest) { Map updatedProperties = new HashMap<>(oldProperties); updatedProperties.put("container.signature.enforcement.digest", enforcementDigest); return updatedProperties; } private void updateSnapshotWithSignatureDigest(Map properties) { try { this.configurationService.updateConfiguration( (String) properties.get(ConfigurationService.KURA_SERVICE_PID), properties, true); } catch (KuraException ex) { logger.error("Impossible to update snapshot for pid {} due to {}", properties.get(ConfigurationService.KURA_SERVICE_PID), ex.getMessage()); } } private void cleanupTemporaryIdentity() { final String identityName = this.currentTemporaryIdentityName.getAndSet(null); clearTemporaryPassword(); if (identityName != null && this.identityService != null) { try { this.identityService.deleteIdentity(identityName); logger.info("Cleaned up temporary identity: {}", identityName); } catch (KuraException e) { logger.warn("Failed to cleanup temporary identity: {}", identityName, e); } } } private void clearTemporaryPassword() { final char[] password = this.currentTemporaryPassword.getAndSet(null); if (password != null) { Arrays.fill(password, '\0'); } } } ================================================ FILE: kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/ContainerInstanceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.container.provider; import static java.util.Objects.isNull; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.container.orchestration.ContainerConfiguration; import org.eclipse.kura.container.orchestration.ContainerConfiguration.ContainerConfigurationBuilder; import org.eclipse.kura.container.orchestration.ContainerNetworkConfiguration; import org.eclipse.kura.container.orchestration.ContainerPort; import org.eclipse.kura.container.orchestration.ImageConfiguration; import org.eclipse.kura.container.orchestration.PasswordRegistryCredentials; import org.eclipse.kura.container.orchestration.PortInternetProtocol; import org.eclipse.kura.container.orchestration.RegistryCredentials; import org.eclipse.kura.util.configuration.Property; public class ContainerInstanceOptions { private static final Property IS_ENABLED = new Property<>("container.enabled", false); private static final Property CONTAINER_IMAGE = new Property<>("container.image", "nginx"); private static final Property CONTAINER_IMAGE_TAG = new Property<>("container.image.tag", "latest"); private static final Property CONTAINER_NAME = new Property<>("kura.service.pid", "kura_test_container"); private static final String ALT_CONTAINER_NAME_PROPERTY = "container.name"; private static final Property CONTAINER_PORTS_EXTERNAL = new Property<>("container.ports.external", ""); private static final Property CONTAINER_PORTS_INTERNAL = new Property<>("container.ports.internal", ""); private static final Property CONTAINER_ENV = new Property<>("container.env", ""); private static final Property CONTAINER_VOLUME = new Property<>("container.volume", ""); private static final Property CONTAINER_DEVICE = new Property<>("container.device", ""); private static final Property CONTAINER_PRIVILEGED = new Property<>("container.privileged", false); private static final Property CONTAINER_IMAGE_DOWNLOAD_RETRIES = new Property<>( "container.image.download.retries", 5); private static final Property CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL = new Property<>( "container.image.download.interval", 30000); private static final Property CONTAINER_LOGGER_PARAMETERS = new Property<>("container.loggerParameters", ""); private static final Property CONTAINER_LOGGING_TYPE = new Property<>("container.loggingType", "default"); private static final Property REGISTRY_URL = new Property<>("registry.hostname", ""); private static final Property REGISTRY_USERNAME = new Property<>("registry.username", ""); private static final Property REGISTRY_PASSWORD = new Property<>("registry.password", ""); private static final Property IMAGES_DOWNLOAD_TIMEOUT = new Property<>("container.image.download.timeout", 500); private static final Property CONTAINER_NETWORKING_MODE = new Property<>("container.networkMode", ""); private static final Property CONTAINER_ENTRY_POINT = new Property<>("container.entrypoint", ""); private static final Property CONTAINER_RESTART_FAILURE = new Property<>("container.restart.onfailure", false); private static final Property CONTAINER_MEMORY = new Property<>("container.memory", ""); private static final Property CONTAINER_CPUS = new Property<>("container.cpus", 1F); private static final Property CONTAINER_GPUS = new Property<>("container.gpus", "all"); private static final Property CONTAINER_RUNTIME = new Property<>("container.runtime", ""); private static final Property SIGNATURE_TRUST_ANCHOR = new Property<>("container.signature.trust.anchor", ""); private static final Property SIGNATURE_VERIFY_TLOG = new Property<>( "container.signature.verify.transparency.log", true); private static final Property ENFORCEMENT_DIGEST = new Property<>("container.signature.enforcement.digest", ""); private static final Property IDENTITY_INTEGRATION_ENABLED = new Property<>("container.identity.enabled", false); private static final Property CONTAINER_PERMISSIONS = new Property<>("container.permissions", ""); private boolean enabled; private final String image; private final String imageTag; private final String containerName; private final List internalPorts; private final List externalPorts; private final List containerPortProtocol; private final String containerEnv; private final String containerVolumeString; private final String containerDevice; private final boolean privilegedMode; private final Map containerVolumes; private final int maxDownloadRetries; private final int retryInterval; private final Map containerLoggingParameters; private final String containerLoggerType; private final Optional registryURL; private final Optional registryUsername; private final Optional registryPassword; private final int imageDownloadTimeout; private final Optional containerNetworkingMode; private final List containerEntryPoint; private final boolean restartOnFailure; private final Optional containerMemory; private final Optional containerCpus; private final Optional containerGpus; private final Optional containerRuntime; private final Optional signatureTrustAnchor; private final Boolean signatureVerifyTransparencyLog; private final Optional enforcementDigest; private final boolean identityIntegrationEnabled; private final List containerPermissions; public ContainerInstanceOptions(final Map properties) { if (isNull(properties)) { throw new IllegalArgumentException("Properties cannot be null!"); } this.enabled = IS_ENABLED.get(properties); this.image = CONTAINER_IMAGE.get(properties); this.imageTag = CONTAINER_IMAGE_TAG.get(properties); this.containerName = resolveContainerName(properties); this.internalPorts = parsePortString(CONTAINER_PORTS_INTERNAL.get(properties)); this.containerPortProtocol = parsePortStringProtocol(CONTAINER_PORTS_INTERNAL.get(properties)); this.externalPorts = parsePortString(CONTAINER_PORTS_EXTERNAL.get(properties)); this.containerEnv = CONTAINER_ENV.get(properties); this.containerVolumeString = CONTAINER_VOLUME.get(properties); this.containerVolumes = parseVolume(this.containerVolumeString); this.containerDevice = CONTAINER_DEVICE.get(properties); this.privilegedMode = CONTAINER_PRIVILEGED.get(properties); this.maxDownloadRetries = CONTAINER_IMAGE_DOWNLOAD_RETRIES.get(properties); this.retryInterval = CONTAINER_IMAGE_DOWNLOAD_RETRY_INTERVAL.get(properties); this.containerLoggerType = CONTAINER_LOGGING_TYPE.get(properties); this.containerLoggingParameters = parseLoggingParams(CONTAINER_LOGGER_PARAMETERS.get(properties)); this.registryURL = REGISTRY_URL.getOptional(properties); this.registryUsername = REGISTRY_USERNAME.getOptional(properties); this.registryPassword = REGISTRY_PASSWORD.getOptional(properties); this.imageDownloadTimeout = IMAGES_DOWNLOAD_TIMEOUT.get(properties); this.containerNetworkingMode = CONTAINER_NETWORKING_MODE.getOptional(properties); this.containerEntryPoint = parseStringListSplitByComma(CONTAINER_ENTRY_POINT.get(properties)); this.restartOnFailure = CONTAINER_RESTART_FAILURE.get(properties); this.containerMemory = parseMemoryString(CONTAINER_MEMORY.getOptional(properties)); this.containerCpus = CONTAINER_CPUS.getOptional(properties); this.containerGpus = parseOptionalString(CONTAINER_GPUS.getOptional(properties)); this.containerRuntime = parseOptionalString(CONTAINER_RUNTIME.getOptional(properties)); this.signatureTrustAnchor = parseOptionalString(SIGNATURE_TRUST_ANCHOR.getOptional(properties)); this.signatureVerifyTransparencyLog = SIGNATURE_VERIFY_TLOG.get(properties); this.enforcementDigest = parseOptionalString(ENFORCEMENT_DIGEST.getOptional(properties)); this.identityIntegrationEnabled = IDENTITY_INTEGRATION_ENABLED.get(properties); this.containerPermissions = parseStringListSplitByComma(CONTAINER_PERMISSIONS.get(properties)); } private String resolveContainerName(final Map properties) { final Object altName = properties.get(ALT_CONTAINER_NAME_PROPERTY); if (altName instanceof String && !((String) altName).isEmpty()) { return (String) altName; } return CONTAINER_NAME.get(properties); } private Map parseVolume(String volumeString) { Map map = new HashMap<>(); if (this.containerVolumeString.isEmpty()) { return map; } for (String entry : volumeString.trim().split(",")) { String[] tempEntry = entry.split(":"); if (tempEntry.length == 2) { map.put(tempEntry[0].trim(), tempEntry[1].trim()); } } return map; } private Map parseLoggingParams(String loggingString) { Map map = new HashMap<>(); if (loggingString.isEmpty()) { return map; } for (String entry : loggingString.trim().split(",")) { String[] tempEntry = entry.split("="); if (tempEntry.length == 2) { map.put(tempEntry[0].trim(), tempEntry[1].trim()); } } return map; } private List parseEnvVars(String containerVolumeString) { List envList = new LinkedList<>(); if (containerVolumeString.isEmpty()) { return envList; } for (String entry : containerVolumeString.trim().split(",")) { envList.add(entry.trim()); } return envList; } private List parseStringListSplitByComma(String stringToSplit) { List stringList = new LinkedList<>(); if (stringToSplit.isEmpty()) { return stringList; } for (String entry : stringToSplit.trim().split(",")) { if (entry.trim().length() > 0) { stringList.add(entry.trim()); } } return stringList; } private Optional parseMemoryString(Optional value) { if (value.isPresent() && !value.get().trim().isEmpty()) { String stringValue = value.get().trim(); long result = 0; switch (stringValue.charAt(stringValue.length() - 1)) { case 'b': result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)); break; case 'k': result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1024L; break; case 'm': result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1048576L; break; case 'g': result = Long.parseLong(stringValue.substring(0, stringValue.length() - 1)) * 1073741824L; break; default: result = Long.parseLong(stringValue); } return Optional.of(result); } else { return Optional.empty(); } } private Optional parseOptionalString(Optional optionalString) { if (optionalString.isPresent() && optionalString.get().isEmpty()) { return Optional.empty(); } else { return optionalString; } } public boolean isEnabled() { return this.enabled; } public String getContainerImage() { return this.image; } public String getContainerImageTag() { return this.imageTag; } public String getContainerName() { return this.containerName; } public List getContainerPortsInternal() { return this.internalPorts; } public List getContainerPortsExternal() { return this.externalPorts; } public Map getContainerVolumeList() { return parseVolume(this.containerVolumeString); } public List getContainerEnvList() { return parseEnvVars(this.containerEnv); } public List getContainerDeviceList() { return parseStringListSplitByComma(this.containerDevice); } public boolean getPrivilegedMode() { return this.privilegedMode; } public boolean isUnlimitedRetries() { return this.maxDownloadRetries == 0; } public int getMaxDownloadRetries() { return this.maxDownloadRetries; } public int getRetryInterval() { return this.retryInterval; } public String getLoggingType() { return this.containerLoggerType; } public boolean getRestartOnFailure() { return this.restartOnFailure; } public Map getLoggerParameters() { return this.containerLoggingParameters; } public Optional getContainerNetworkingMode() { return this.containerNetworkingMode; } public Optional getRegistryCredentials() { if (this.registryUsername.isPresent() && this.registryPassword.isPresent()) { return Optional.of(new PasswordRegistryCredentials(this.registryURL, this.registryUsername.get(), new Password(this.registryPassword.get()))); } return Optional.empty(); } public int getImageDownloadTimeout() { return this.imageDownloadTimeout; } private ContainerNetworkConfiguration buildContainerNetworkConfig() { return new ContainerNetworkConfiguration.ContainerNetworkConfigurationBuilder() .setNetworkMode(getContainerNetworkingMode()).build(); } public List getEntryPoint() { return this.containerEntryPoint; } public Optional getMemory() { return this.containerMemory; } public Optional getCpus() { return this.containerCpus; } public Optional getGpus() { return this.containerGpus; } public Optional getRuntime() { return this.containerRuntime; } public Optional getSignatureTrustAnchor() { return this.signatureTrustAnchor; } public Boolean getSignatureVerifyTransparencyLog() { return this.signatureVerifyTransparencyLog; } public Optional getEnforcementDigest() { return this.enforcementDigest; } public boolean isIdentityIntegrationEnabled() { return this.identityIntegrationEnabled; } public List getContainerPermissions() { return this.containerPermissions; } private ImageConfiguration buildImageConfig() { return new ImageConfiguration.ImageConfigurationBuilder().setImageName(this.image).setImageTag(this.imageTag) .setImageDownloadTimeoutSeconds(this.imageDownloadTimeout) .setRegistryCredentials(getRegistryCredentials()).build(); } private ContainerConfigurationBuilder buildPortConfig(ContainerConfigurationBuilder cc) { List containerPorts = new LinkedList<>(); Iterator internalIt = this.internalPorts.iterator(); Iterator externalIt = this.externalPorts.iterator(); Iterator ipIt = this.containerPortProtocol.iterator(); while (externalIt.hasNext() && internalIt.hasNext() && ipIt.hasNext()) { containerPorts.add(new ContainerPort(internalIt.next(), externalIt.next(), ipIt.next())); } cc.setContainerPorts(containerPorts); return cc; } public ContainerConfiguration getContainerConfiguration() { return buildPortConfig(ContainerConfiguration.builder()).setContainerName(getContainerName()) .setImageConfiguration(buildImageConfig()).setEnvVars(getContainerEnvList()) .setVolumes(getContainerVolumeList()).setPrivilegedMode(this.privilegedMode) .setDeviceList(getContainerDeviceList()).setFrameworkManaged(true).setLoggingType(getLoggingType()) .setContainerNetowrkConfiguration(buildContainerNetworkConfig()) .setLoggerParameters(getLoggerParameters()).setEntryPoint(getEntryPoint()) .setRestartOnFailure(getRestartOnFailure()).setMemory(getMemory()).setCpus(getCpus()).setGpus(getGpus()) .setRuntime(getRuntime()).setEnforcementDigest(getEnforcementDigest()).build(); } private List parsePortString(String ports) { List tempArray = new ArrayList<>(); if (!ports.isEmpty()) { String[] tempString = ports.trim().replace(" ", "").split(","); for (String element : tempString) { tempArray.add(Integer.parseInt(element.trim().replace("-", "").split(":")[0])); } } return tempArray; } private List parsePortStringProtocol(String ports) { List tempArray = new ArrayList<>(); if (!ports.isEmpty()) { for (String portToken : ports.trim().replace(" ", "").split(",")) { if (portToken.split(":").length > 1) { switch (portToken.split(":")[1].toUpperCase().trim()) { case "UDP": tempArray.add(PortInternetProtocol.UDP); break; case "SCTP": tempArray.add(PortInternetProtocol.SCTP); break; default: tempArray.add(PortInternetProtocol.TCP); break; } } else { // if setting is not used add TCP by default. tempArray.add(PortInternetProtocol.TCP); } } } return tempArray; } @Override public int hashCode() { return Objects.hash(containerCpus, containerDevice, containerEntryPoint, containerEnv, containerGpus, containerLoggerType, containerLoggingParameters, containerMemory, containerName, containerNetworkingMode, containerPermissions, containerPortProtocol, containerRuntime, containerVolumeString, containerVolumes, enabled, enforcementDigest, externalPorts, identityIntegrationEnabled, image, imageDownloadTimeout, imageTag, internalPorts, maxDownloadRetries, privilegedMode, registryPassword, registryURL, registryUsername, restartOnFailure, retryInterval, signatureTrustAnchor, signatureVerifyTransparencyLog); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } ContainerInstanceOptions other = (ContainerInstanceOptions) obj; return Objects.equals(containerCpus, other.containerCpus) && Objects.equals(containerDevice, other.containerDevice) && Objects.equals(containerEntryPoint, other.containerEntryPoint) && Objects.equals(containerEnv, other.containerEnv) && Objects.equals(containerGpus, other.containerGpus) && Objects.equals(containerLoggerType, other.containerLoggerType) && Objects.equals(containerLoggingParameters, other.containerLoggingParameters) && Objects.equals(containerMemory, other.containerMemory) && Objects.equals(containerName, other.containerName) && Objects.equals(containerNetworkingMode, other.containerNetworkingMode) && Objects.equals(containerPermissions, other.containerPermissions) && Objects.equals(containerPortProtocol, other.containerPortProtocol) && Objects.equals(containerVolumeString, other.containerVolumeString) && Objects.equals(containerVolumes, other.containerVolumes) && enabled == other.enabled && Objects.equals(enforcementDigest, other.enforcementDigest) && Objects.equals(externalPorts, other.externalPorts) && identityIntegrationEnabled == other.identityIntegrationEnabled && Objects.equals(image, other.image) && imageDownloadTimeout == other.imageDownloadTimeout && Objects.equals(imageTag, other.imageTag) && Objects.equals(internalPorts, other.internalPorts) && maxDownloadRetries == other.maxDownloadRetries && privilegedMode == other.privilegedMode && Objects.equals(registryPassword, other.registryPassword) && Objects.equals(registryURL, other.registryURL) && Objects.equals(registryUsername, other.registryUsername) && restartOnFailure == other.restartOnFailure && retryInterval == other.retryInterval && Objects.equals(containerRuntime, other.containerRuntime) && Objects.equals(signatureTrustAnchor, other.signatureTrustAnchor) && Objects.equals(signatureVerifyTransparencyLog, other.signatureVerifyTransparencyLog); } } ================================================ FILE: kura/org.eclipse.kura.container.provider/src/main/java/org/eclipse/kura/container/provider/PasswordGenerator.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.container.provider; import java.security.SecureRandom; import java.util.Random; import org.eclipse.kura.KuraException; import org.eclipse.kura.identity.PasswordStrengthRequirements; public class PasswordGenerator { private static final char[] SPECIAL_CHARS = { '!', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '?', '@', '[', ']', '^', '_', '{', '|', '~' }; private static final int SPECIAL_CHARS_BOUND = SPECIAL_CHARS.length; private static final int DIGITS_BOUND = SPECIAL_CHARS_BOUND + ((int) '9' - (int) '0' + 1); private static final int LOWERCASE_BOUND = DIGITS_BOUND + ((int) 'z' - (int) 'a' + 1); private static final int UPPERCASE_BOUND = LOWERCASE_BOUND + ((int) 'Z' - (int) 'A' + 1); private static final Random RANDOM = new SecureRandom(); private PasswordGenerator() { } private static char charInRange(final Random random, final char lower, final char upper) { return (char) random.nextInt((int) lower, ((int) upper) + 1); } private static int freeIndex(final Random random, final char[] values) { int result; do { result = random.nextInt(values.length); } while (values[result] != '\u0000'); return result; } public static char[] generatePassword(final PasswordStrengthRequirements requirements) throws KuraException { final char[] pwd = new char[Math.max(32, requirements.getPasswordMinimumLength())]; if (requirements.digitsRequired()) { pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, '0', '9'); } if (requirements.specialCharactersRequired()) { pwd[freeIndex(RANDOM, pwd)] = SPECIAL_CHARS[RANDOM.nextInt(SPECIAL_CHARS.length)]; } if (requirements.bothCasesRequired()) { pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, 'A', 'Z'); pwd[freeIndex(RANDOM, pwd)] = charInRange(RANDOM, 'a', 'z'); } for (int i = 0; i < pwd.length; i++) { if (pwd[i] != '\u0000') { continue; } final int index = RANDOM.nextInt(UPPERCASE_BOUND); char result; if (index < SPECIAL_CHARS_BOUND) { result = SPECIAL_CHARS[index]; } else if (index < DIGITS_BOUND) { result = (char) ((int) '0' + (index - SPECIAL_CHARS_BOUND)); } else if (index < LOWERCASE_BOUND) { result = (char) ((int) 'a' + (index - DIGITS_BOUND)); } else { result = (char) ((int) 'A' + (index - LOWERCASE_BOUND)); } pwd[i] = result; } return pwd; } } ================================================ FILE: kura/org.eclipse.kura.core/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core Bundle-SymbolicName: org.eclipse.kura.core;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Export-Package: org.eclipse.kura.core.linux.executor;version="1.0.0", org.eclipse.kura.core.linux.util;version="1.2.0", org.eclipse.kura.core.ssl;version="1.0.0", org.eclipse.kura.core.util;version="2.0.0";x-internal:=true Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: javax.crypto, javax.naming, javax.net, javax.net.ssl, javax.sql, org.apache.commons.exec;version="1.3.0", org.apache.commons.exec.environment;version="1.3.0", org.apache.commons.exec.util;version="1.3.0", org.apache.commons.io;version="[2.4,3.0)", org.apache.commons.io.output;version="2.4.0", org.bouncycastle.asn1.x500;version="1.78.1", org.bouncycastle.openssl.jcajce;version="1.78.1", org.bouncycastle.operator;version="1.78.1", org.bouncycastle.operator.jcajce;version="1.78.1", org.bouncycastle.pkcs;version="1.78.1", org.bouncycastle.pkcs.jcajce;version="1.78.1", org.bouncycastle.util.io.pem;version="1.78.1", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.certificate;version="[2.0,3.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.connection.listener;version="[1.0,2.0)", org.eclipse.kura.core.ssl;version="1.0.0", org.eclipse.kura.crypto;version="[1.0,2.0)", org.eclipse.kura.db;version="[2.0,2.1)", org.eclipse.kura.executor;version="[1.0,2.0)", org.eclipse.kura.message.store;version="[1.0,2.0)", org.eclipse.kura.message.store.provider;version="[1.0,1.1)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.security.keystore;version="[1.0,2.0)", org.eclipse.kura.ssl;version="[2.1,2.2)", org.eclipse.kura.system;version="[1.4,2.0)", org.eclipse.kura.type;version="[1.1,2.0)", org.eclipse.kura.util.configuration;version="[1.0,2.0)", org.eclipse.kura.util.jdbc;version="[1.0,2.0)", org.eclipse.kura.watchdog;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.4.0", org.osgi.util.tracker;version="1.5.0", org.quartz;version="2.3.2", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/org.eclipse.kura.core/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html src.includes = about.html,\ about_files/ additional.bundles = org.osgi.service.component.annotations,\ org.osgi.service.metatype.annotations ================================================ FILE: kura/org.eclipse.kura.core/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml org.eclipse.kura.core 2.0.0-SNAPSHOT eclipse-plugin biz.aQute.bnd bnd-maven-plugin ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/ExecutorUtil.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.internal.linux.executor; import static java.nio.charset.StandardCharsets.UTF_8; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.function.Consumer; import java.util.stream.Collectors; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.exec.environment.EnvironmentUtils; import org.apache.commons.io.output.NullOutputStream; import org.eclipse.kura.core.linux.executor.LinuxExitStatus; import org.eclipse.kura.core.linux.executor.LinuxPid; import org.eclipse.kura.core.linux.executor.LinuxResultHandler; import org.eclipse.kura.core.linux.executor.LinuxSignal; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandStatus; import org.eclipse.kura.executor.Pid; import org.eclipse.kura.executor.Signal; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ExecutorUtil { private static final Logger logger = LoggerFactory.getLogger(ExecutorUtil.class); private static final String COMMAND_MESSAGE = "Command "; private static final String FAILED_TO_GET_PID_MESSAGE = "Failed to get pid for command '{}'"; private static final File TEMP_DIR = new File(System.getProperty("java.io.tmpdir")); private static final String DEFAULT_COMMAND_USERNAME = "kura"; private String commandUsername; public ExecutorUtil() { this.commandUsername = DEFAULT_COMMAND_USERNAME; } public ExecutorUtil(String commandUsername) { this.commandUsername = commandUsername; } public String getCommandUsername() { return commandUsername; } public void setCommandUsername(String commandUsername) { this.commandUsername = commandUsername; } public CommandStatus executeUnprivileged(Command command) { CommandLine commandLine = buildUnprivilegedCommand(command); return executeSync(command, commandLine); } public void executeUnprivileged(Command command, Consumer callback) { CommandLine commandLine = buildUnprivilegedCommand(command); executeAsync(command, commandLine, callback); } public CommandStatus executePrivileged(Command command) { CommandLine commandLine = buildPrivilegedCommand(command); return executeSync(command, commandLine); } public void executePrivileged(Command command, Consumer callback) { CommandLine commandLine = buildPrivilegedCommand(command); executeAsync(command, commandLine, callback); } public boolean stopUnprivileged(Pid pid, Signal signal) { boolean isStopped = true; if (isRunning(pid)) { Command killCommand = new Command(buildKillCommand(pid, signal)); killCommand.setTimeout(60); killCommand.setSignal(signal); CommandStatus commandStatus = executeUnprivileged(killCommand); isStopped = commandStatus.getExitStatus().isSuccessful(); } return isStopped; } public boolean killUnprivileged(String[] commandLine, Signal signal) { boolean isKilled = true; Map pids = getPids(commandLine); for (Pid pid : pids.values()) { isKilled &= stopUnprivileged(pid, signal); } return isKilled; } public boolean stopPrivileged(Pid pid, Signal signal) { boolean isStopped = true; if (isRunning(pid)) { Command killCommand = new Command(buildKillCommand(pid, signal)); killCommand.setTimeout(60); killCommand.setSignal(signal); CommandStatus commandStatus = executePrivileged(killCommand); isStopped = commandStatus.getExitStatus().isSuccessful(); } return isStopped; } public boolean killPrivileged(String[] commandLine, Signal signal) { boolean isKilled = true; Map pids = getPids(commandLine); for (Pid pid : pids.values()) { isKilled &= stopPrivileged(pid, signal); } return isKilled; } public boolean isRunning(Pid pid) { boolean isRunning = false; String pidString = ((Integer) pid.getPid()).toString(); String psCommand = "ps -p " + pidString; CommandLine commandLine = CommandLine.parse(psCommand); Executor executor = getExecutor(); final ByteArrayOutputStream out = createStream(); final ByteArrayOutputStream err = createStream(); final PumpStreamHandler handler = new PumpStreamHandler(out, err); executor.setStreamHandler(handler); executor.setWorkingDirectory(TEMP_DIR); executor.setExitValue(0); int exitValue; try { exitValue = executor.execute(commandLine); if (exitValue == 0 && new String(out.toByteArray(), UTF_8).contains(pidString)) { isRunning = true; } } catch (IOException e) { logger.warn("Failed to check if process with pid {} is running", pidString); } return isRunning; } public boolean isRunning(String[] commandLine) { return !getPids(commandLine).isEmpty(); } public Map getPids(String[] commandLine) { Map pids = new HashMap<>(); CommandLine psCommandLine = new CommandLine("ps"); psCommandLine.addArgument("-ax"); Executor executor = getExecutor(); final ByteArrayOutputStream out = createStream(); final ByteArrayOutputStream err = createStream(); final PumpStreamHandler handler = new PumpStreamHandler(out, err); executor.setStreamHandler(handler); executor.setWorkingDirectory(TEMP_DIR); executor.setExitValue(0); int exitValue = 1; try { exitValue = executor.execute(psCommandLine); } catch (IOException e) { logger.debug(FAILED_TO_GET_PID_MESSAGE, commandLine, e); } if (exitValue == 0) { pids = parsePids(out, commandLine); } return pids; } public static void stopStreamHandler(Executor executor) { try { if (executor.getStreamHandler() != null) { executor.getStreamHandler().stop(); } } catch (IOException e) { logger.warn("Failed to stop stream handlers", e); } } private Map parsePids(ByteArrayOutputStream out, String[] commandLine) { Map pids = new HashMap<>(); String pid; String[] output = new String(out.toByteArray(), UTF_8).split("\n"); for (String line : output) { StringTokenizer st = new StringTokenizer(line); pid = st.nextToken(); st.nextElement(); st.nextElement(); st.nextElement(); // get the remainder of the line showing the command that was issued line = line.substring(line.indexOf(st.nextToken())); if (checkLine(line, commandLine)) { pids.put(line, Integer.parseInt(pid)); } } // Sort pids in reverse order (useful when stop processes...) return pids.entrySet().stream().sorted(Map.Entry.comparingByValue().reversed()) .collect(Collectors.toMap(Map.Entry::getKey, e -> new LinuxPid(e.getValue()), (e1, e2) -> e1, LinkedHashMap::new)); } private boolean checkLine(String line, String[] tokens) { return Arrays.stream(tokens).parallel().allMatch(line::contains); } private CommandStatus executeSync(Command command, CommandLine commandLine) { CommandStatus commandStatus = new CommandStatus(command, new LinuxExitStatus(0)); commandStatus.setOutputStream(command.getOutputStream()); commandStatus.setErrorStream(command.getErrorStream()); commandStatus.setInputStream(command.getInputStream()); Executor executor = configureExecutor(command); int exitStatus = 0; logger.debug("Executing: {}", commandLine); try { Map environment = command.getEnvironment(); if (environment != null && !environment.isEmpty()) { Map currentEnv = EnvironmentUtils.getProcEnvironment(); currentEnv.putAll(environment); exitStatus = executor.execute(commandLine, currentEnv); } else { exitStatus = executor.execute(commandLine); } } catch (ExecuteException e) { exitStatus = e.getExitValue(); logger.debug(COMMAND_MESSAGE + " {} returned error code {}", commandLine, exitStatus, e); } catch (IOException e) { exitStatus = 1; logger.debug(COMMAND_MESSAGE + " {} failed", commandLine, e); } finally { stopStreamHandler(executor); commandStatus.setExitStatus(new LinuxExitStatus(exitStatus)); commandStatus.setTimedout(executor.getWatchdog().killedProcess()); } return commandStatus; } private Executor configureExecutor(Command command) { Executor executor = getExecutor(); int timeout = command.getTimeout(); ExecuteWatchdog watchdog = timeout <= 0 ? new ExecuteWatchdog(ExecuteWatchdog.INFINITE_TIMEOUT) : new ExecuteWatchdog(timeout * 1000L); executor.setWatchdog(watchdog); OutputStream out = command.getOutputStream(); OutputStream err = command.getErrorStream(); InputStream in = command.getInputStream(); FlushPumpStreamHandler handler; if (out != null && err != null) { handler = new FlushPumpStreamHandler(out, err, in); } else if (out != null) { handler = new FlushPumpStreamHandler(out, new NullOutputStream(), in); } else if (err != null) { handler = new FlushPumpStreamHandler(new NullOutputStream(), err, in); } else { handler = new FlushPumpStreamHandler(new NullOutputStream(), new NullOutputStream(), in); } executor.setStreamHandler(handler); String directory = command.getDirectory(); File workingDir = directory == null || directory.isEmpty() || !Files.isDirectory(Paths.get(directory)) ? TEMP_DIR : new File(directory); executor.setWorkingDirectory(workingDir); return executor; } protected Executor getExecutor() { return new DefaultExecutor(); } private void executeAsync(Command command, CommandLine commandLine, Consumer callback) { CommandStatus commandStatus = new CommandStatus(command, new LinuxExitStatus(0)); commandStatus.setOutputStream(command.getOutputStream()); commandStatus.setErrorStream(command.getErrorStream()); commandStatus.setInputStream(command.getInputStream()); Executor executor = configureExecutor(command); LinuxResultHandler resultHandler = new LinuxResultHandler(callback, executor); resultHandler.setStatus(commandStatus); logger.debug("Executing: {}", commandLine); try { Map environment = command.getEnvironment(); if (environment != null && !environment.isEmpty()) { Map currentEnv = EnvironmentUtils.getProcEnvironment(); currentEnv.putAll(environment); executor.execute(commandLine, currentEnv, resultHandler); } else { executor.execute(commandLine, resultHandler); } } catch (IOException e) { stopStreamHandler(executor); commandStatus.setExitStatus(new LinuxExitStatus(1)); logger.error(COMMAND_MESSAGE + commandLine + " failed", e); } } private String[] buildKillCommand(Pid pid, Signal signal) { Integer pidNumber = pid.getPid(); if (logger.isInfoEnabled()) { logger.info("Attempting to send {} to process with pid {}", ((LinuxSignal) signal).name(), pidNumber); } return new String[] { "kill", "-" + signal.getSignalNumber(), String.valueOf(pidNumber) }; } private CommandLine buildUnprivilegedCommand(Command command) { // Build the command as follows: // su -c "VARS... timeout -s " // or su c "VARS... sh -c " // The timeout command is added because the commons-exec doesn't allow to set the signal to send for killing a // process after a timeout CommandLine commandLine = new CommandLine("su"); commandLine.addArgument(this.commandUsername); commandLine.addArgument("-c"); List c = new ArrayList<>(); Map env = command.getEnvironment(); if (env != null && !env.isEmpty()) { env.entrySet().stream().forEach(entry -> c.add(entry.getKey() + "=" + entry.getValue())); } int timeout = command.getTimeout(); if (timeout != -1) { c.add("timeout"); c.add("-s"); c.add(((LinuxSignal) command.getSignal()).name()); c.add(Integer.toString(timeout)); } Arrays.asList(command.getCommandLine()).stream().forEach(c::add); commandLine.addArgument(String.join(" ", c), false); return commandLine; } private CommandLine buildPrivilegedCommand(Command command) { CommandLine commandLine; if (command.isExecutedInAShell()) { commandLine = new CommandLine("/bin/sh"); commandLine.addArgument("-c"); commandLine.addArgument(command.toString(), false); } else { String[] tokens = command.getCommandLine(); commandLine = new CommandLine(tokens[0]); for (int i = 1; i < tokens.length; i++) { commandLine.addArgument(tokens[i], false); } } return commandLine; } protected ByteArrayOutputStream createStream() { return new ByteArrayOutputStream(); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/FlushPumpStreamHandler.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.internal.linux.executor; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.exec.PumpStreamHandler; public class FlushPumpStreamHandler extends PumpStreamHandler { public FlushPumpStreamHandler(final OutputStream out, final OutputStream err, final InputStream input) { super(out, err, input); } @Override protected Thread createPump(final InputStream is, final OutputStream os, final boolean closeWhenExhausted) { final Thread result = new Thread(new FlushStreamPumper(is, os, closeWhenExhausted), "Exec Stream Pumper"); result.setDaemon(true); return result; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/internal/linux/executor/FlushStreamPumper.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.internal.linux.executor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.exec.StreamPumper; import org.apache.commons.exec.util.DebugUtils; public class FlushStreamPumper extends StreamPumper { private static final int DEFAULT_SIZE = 1024; private final InputStream is; private final OutputStream os; private final int size; private boolean finished; private final boolean closeWhenExhausted; public FlushStreamPumper(InputStream is, OutputStream os, boolean closeWhenExhausted) { super(is, os, closeWhenExhausted); this.is = is; this.os = os; this.size = DEFAULT_SIZE; this.closeWhenExhausted = closeWhenExhausted; } @Override public void run() { synchronized (this) { // Just in case this object is reused in the future this.finished = false; } final byte[] buf = new byte[this.size]; int length; try { while ((length = this.is.read(buf)) > 0) { this.os.write(buf, 0, length); this.os.flush(); } } catch (final Exception e) { // nothing to do } finally { if (this.closeWhenExhausted) { try { this.os.close(); } catch (final IOException e) { final String msg = "Got exception while closing exhausted output stream"; DebugUtils.handleException(msg, e); } } synchronized (this) { this.finished = true; notifyAll(); } } } @Override public synchronized boolean isFinished() { return this.finished; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxExitStatus.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor; import org.eclipse.kura.executor.ExitStatus; public class LinuxExitStatus implements ExitStatus { private final int exitValue; public LinuxExitStatus(int exitStatus) { this.exitValue = exitStatus; } @Override public int getExitCode() { return this.exitValue; } @Override public boolean isSuccessful() { return this.exitValue == 0; } @Override public String toString() { return String.valueOf(this.exitValue); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.exitValue; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } LinuxExitStatus other = (LinuxExitStatus) obj; return this.exitValue == other.exitValue; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxPid.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor; import org.eclipse.kura.executor.Pid; public class LinuxPid implements Pid { private final int pid; public LinuxPid(int pid) { this.pid = pid; } @Override public int getPid() { return this.pid; } @Override public String toString() { return String.valueOf(this.pid); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.pid; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } LinuxPid other = (LinuxPid) obj; return this.pid == other.pid; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxResultHandler.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor; import java.util.function.Consumer; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteResultHandler; import org.apache.commons.exec.Executor; import org.eclipse.kura.core.internal.linux.executor.ExecutorUtil; import org.eclipse.kura.executor.CommandStatus; public class LinuxResultHandler implements ExecuteResultHandler { private static final int TIMEOUT_EXIT_VALUE = 124; private static final int SIGTERM_EXIT_VALUE = 143; private final Consumer callback; private CommandStatus commandStatus; private Executor executor; public LinuxResultHandler(Consumer callback, Executor executor) { this.callback = callback; this.executor = executor; } public CommandStatus getStatus() { return this.commandStatus; } public void setStatus(CommandStatus status) { this.commandStatus = status; } @Override public void onProcessComplete(int exitValue) { ExecutorUtil.stopStreamHandler(this.executor); this.commandStatus.setExitStatus(new LinuxExitStatus(exitValue)); this.callback.accept(this.commandStatus); } @Override public void onProcessFailed(ExecuteException e) { ExecutorUtil.stopStreamHandler(this.executor); this.commandStatus.setExitStatus(new LinuxExitStatus(e.getExitValue())); // The PrivilegedExecutorService kills a command with SIGTERM and exits with 143 when timedout; the // UnprivilegedExecutorService uses timeout command that exits with 124. if (e.getExitValue() == TIMEOUT_EXIT_VALUE || e.getExitValue() == SIGTERM_EXIT_VALUE) { this.commandStatus.setTimedout(true); } this.callback.accept(this.commandStatus); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/LinuxSignal.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor; import org.eclipse.kura.executor.Signal; public enum LinuxSignal implements Signal { SIGHUP { @Override public int getSignalNumber() { return 1; } }, SIGINT { @Override public int getSignalNumber() { return 2; } }, SIGQUIT { @Override public int getSignalNumber() { return 3; } }, SIGILL { @Override public int getSignalNumber() { return 4; } }, SIGTRAP { @Override public int getSignalNumber() { return 5; } }, SIGABRT { @Override public int getSignalNumber() { return 6; } }, SIGBUS { @Override public int getSignalNumber() { return 7; } }, SIGFPE { @Override public int getSignalNumber() { return 8; } }, SIGKILL { @Override public int getSignalNumber() { return 9; } }, SIGUSR1 { @Override public int getSignalNumber() { return 10; } }, SIGSEGV { @Override public int getSignalNumber() { return 11; } }, SIGUSR2 { @Override public int getSignalNumber() { return 12; } }, SIGPIPE { @Override public int getSignalNumber() { return 13; } }, SIGALRM { @Override public int getSignalNumber() { return 14; } }, SIGTERM { @Override public int getSignalNumber() { return 15; } }, SIGSTKFLT { @Override public int getSignalNumber() { return 16; } }, SIGCHLD { @Override public int getSignalNumber() { return 17; } }, SIGCONT { @Override public int getSignalNumber() { return 18; } }, SIGSTOP { @Override public int getSignalNumber() { return 19; } }, SIGTSTP { @Override public int getSignalNumber() { return 20; } }, SIGTTIN { @Override public int getSignalNumber() { return 21; } }, SIGTTOU { @Override public int getSignalNumber() { return 22; } }, SIGURG { @Override public int getSignalNumber() { return 23; } }, SIGXCPU { @Override public int getSignalNumber() { return 24; } }, SIGXFSZ { @Override public int getSignalNumber() { return 25; } }, SIGVTALRM { @Override public int getSignalNumber() { return 26; } }, SIGPROF { @Override public int getSignalNumber() { return 27; } }, SIGWINCH { @Override public int getSignalNumber() { return 28; } }, SIGIO { @Override public int getSignalNumber() { return 29; } }, SIGPWR { @Override public int getSignalNumber() { return 30; } }, SIGSYS { @Override public int getSignalNumber() { return 31; } }, SIGRTMIN { @Override public int getSignalNumber() { return 34; } }, SIGRTMIN_PLUS_1 { @Override public int getSignalNumber() { return 35; } }, SIGRTMIN_PLUS_2 { @Override public int getSignalNumber() { return 36; } }, SIGRTMIN_PLUS_3 { @Override public int getSignalNumber() { return 37; } }, SIGRTMIN_PLUS_4 { @Override public int getSignalNumber() { return 38; } }, SIGRTMIN_PLUS_5 { @Override public int getSignalNumber() { return 39; } }, SIGRTMIN_PLUS_6 { @Override public int getSignalNumber() { return 40; } }, SIGRTMIN_PLUS_7 { @Override public int getSignalNumber() { return 41; } }, SIGRTMIN_PLUS_8 { @Override public int getSignalNumber() { return 42; } }, SIGRTMIN_PLUS_9 { @Override public int getSignalNumber() { return 43; } }, SIGRTMIN_PLUS_10 { @Override public int getSignalNumber() { return 44; } }, SIGRTMIN_PLUS_11 { @Override public int getSignalNumber() { return 45; } }, SIGRTMIN_PLUS_12 { @Override public int getSignalNumber() { return 46; } }, SIGRTMIN_PLUS_13 { @Override public int getSignalNumber() { return 47; } }, SIGRTMIN_PLUS_14 { @Override public int getSignalNumber() { return 48; } }, SIGRTMIN_PLUS_15 { @Override public int getSignalNumber() { return 49; } }, SIGRTMAX_MINUS_14 { @Override public int getSignalNumber() { return 50; } }, SIGRTMAX_MINUS_13 { @Override public int getSignalNumber() { return 51; } }, SIGRTMAX_MINUS_12 { @Override public int getSignalNumber() { return 52; } }, SIGRTMAX_MINUS_11 { @Override public int getSignalNumber() { return 53; } }, SIGRTMAX_MINUS_10 { @Override public int getSignalNumber() { return 54; } }, SIGRTMAX_MINUS_9 { @Override public int getSignalNumber() { return 55; } }, SIGRTMAX_MINUS_8 { @Override public int getSignalNumber() { return 56; } }, SIGRTMAX_MINUS_7 { @Override public int getSignalNumber() { return 57; } }, SIGRTMAX_MINUS_6 { @Override public int getSignalNumber() { return 58; } }, SIGRTMAX_MINUS_5 { @Override public int getSignalNumber() { return 59; } }, SIGRTMAX_MINUS_4 { @Override public int getSignalNumber() { return 60; } }, SIGRTMAX_MINUS_3 { @Override public int getSignalNumber() { return 61; } }, SIGRTMAX_MINUS_2 { @Override public int getSignalNumber() { return 62; } }, SIGRTMAX_MINUS_1 { @Override public int getSignalNumber() { return 63; } }, SIGRTMAX { @Override public int getSignalNumber() { return 64; } }; } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/privileged/PrivilegedExecutorServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor.privileged; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Map; import java.util.function.Consumer; import org.apache.commons.io.Charsets; import org.eclipse.kura.core.internal.linux.executor.ExecutorUtil; import org.eclipse.kura.core.linux.executor.LinuxExitStatus; import org.eclipse.kura.core.linux.executor.LinuxSignal; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandStatus; import org.eclipse.kura.executor.Pid; import org.eclipse.kura.executor.PrivilegedExecutorService; import org.eclipse.kura.executor.Signal; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(immediate = true, // name = "org.eclipse.kura.executor.PrivilegedExecutorService", // property = "service.pid=org.eclipse.kura.executor.PrivilegedExecutorService") public class PrivilegedExecutorServiceImpl implements PrivilegedExecutorService { private static final Logger logger = LoggerFactory.getLogger(PrivilegedExecutorServiceImpl.class); private static final LinuxSignal DEFAULT_SIGNAL = LinuxSignal.SIGTERM; private ExecutorUtil executorUtil; @SuppressWarnings("unused") private ComponentContext ctx; @Activate public void activate(ComponentContext componentContext) { logger.info("activate..."); this.ctx = componentContext; this.executorUtil = new ExecutorUtil(); } @Deactivate public void deactivate(ComponentContext componentContext) { logger.info("deactivate..."); this.ctx = null; } @Override public CommandStatus execute(Command command) { if (command.getCommandLine() == null || command.getCommandLine().length == 0) { return buildErrorStatus(command); } if (command.getSignal() == null) { command.setSignal(DEFAULT_SIGNAL); } return this.executorUtil.executePrivileged(command); } @Override public void execute(Command command, Consumer callback) { if (command.getCommandLine() == null || command.getCommandLine().length == 0) { callback.accept(buildErrorStatus(command)); return; } if (command.getSignal() == null) { command.setSignal(DEFAULT_SIGNAL); } this.executorUtil.executePrivileged(command, callback); } @Override public boolean stop(Pid pid, Signal signal) { boolean isStopped = false; if (signal == null) { isStopped = this.executorUtil.stopPrivileged(pid, DEFAULT_SIGNAL); } else { isStopped = this.executorUtil.stopPrivileged(pid, signal); } return isStopped; } @Override public boolean kill(String[] commandLine, Signal signal) { boolean isKilled = false; if (signal == null) { isKilled = this.executorUtil.killPrivileged(commandLine, DEFAULT_SIGNAL); } else { isKilled = this.executorUtil.killPrivileged(commandLine, signal); } return isKilled; } @Override public boolean isRunning(Pid pid) { return this.executorUtil.isRunning(pid); } @Override public boolean isRunning(String[] commandLine) { return this.executorUtil.isRunning(commandLine); } @Override public Map getPids(String[] commandLine) { return this.executorUtil.getPids(commandLine); } private CommandStatus buildErrorStatus(Command command) { CommandStatus status = new CommandStatus(command, new LinuxExitStatus(1)); ByteArrayOutputStream err = new ByteArrayOutputStream(); try { err.write("The commandLine cannot be empty or not defined".getBytes(Charsets.UTF_8)); } catch (IOException e) { logger.error("Cannot write to error stream", e); } status.setErrorStream(err); return status; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/executor/unprivileged/UnprivilegedExecutorServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.executor.unprivileged; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Map; import java.util.function.Consumer; import org.apache.commons.io.Charsets; import org.eclipse.kura.core.internal.linux.executor.ExecutorUtil; import org.eclipse.kura.core.linux.executor.LinuxExitStatus; import org.eclipse.kura.core.linux.executor.LinuxSignal; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandStatus; import org.eclipse.kura.executor.Pid; import org.eclipse.kura.executor.Signal; import org.eclipse.kura.executor.UnprivilegedExecutorService; import org.eclipse.kura.system.SystemService; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "org.eclipse.kura.executor.UnprivilegedExecutorService", // property = "service.pid=org.eclipse.kura.executor.UnprivilegedExecutorService" // ) public class UnprivilegedExecutorServiceImpl implements UnprivilegedExecutorService { private static final Logger logger = LoggerFactory.getLogger(UnprivilegedExecutorServiceImpl.class); private static final LinuxSignal DEFAULT_SIGNAL = LinuxSignal.SIGTERM; private final ExecutorUtil executorUtil; @Activate public UnprivilegedExecutorServiceImpl(final @Reference SystemService systemService) { logger.info("activate..."); String user = systemService.getCommandUser(); if (user == null || user.equals("unknown")) { this.executorUtil = new ExecutorUtil(); } else { this.executorUtil = new ExecutorUtil(user); } } @Deactivate protected void deactivate() { logger.info("deactivate..."); } @Override public CommandStatus execute(Command command) { if (command.getCommandLine() == null || command.getCommandLine().length == 0) { return buildErrorStatus(command); } if (command.getSignal() == null) { command.setSignal(DEFAULT_SIGNAL); } return this.executorUtil.executeUnprivileged(command); } @Override public void execute(Command command, Consumer callback) { if (command.getCommandLine() == null || command.getCommandLine().length == 0) { callback.accept(buildErrorStatus(command)); return; } if (command.getSignal() == null) { command.setSignal(DEFAULT_SIGNAL); } this.executorUtil.executeUnprivileged(command, callback); } @Override public boolean stop(Pid pid, Signal signal) { boolean isStopped = false; if (signal == null) { isStopped = this.executorUtil.stopUnprivileged(pid, DEFAULT_SIGNAL); } else { isStopped = this.executorUtil.stopUnprivileged(pid, signal); } return isStopped; } @Override public boolean kill(String[] commandLine, Signal signal) { boolean isKilled = false; if (signal == null) { isKilled = this.executorUtil.killUnprivileged(commandLine, DEFAULT_SIGNAL); } else { isKilled = this.executorUtil.killUnprivileged(commandLine, signal); } return isKilled; } @Override public boolean isRunning(Pid pid) { return this.executorUtil.isRunning(pid); } @Override public boolean isRunning(String[] commandLine) { return this.executorUtil.isRunning(commandLine); } @Override public Map getPids(String[] commandLine) { return this.executorUtil.getPids(commandLine); } private CommandStatus buildErrorStatus(Command command) { CommandStatus status = new CommandStatus(command, new LinuxExitStatus(1)); ByteArrayOutputStream err = new ByteArrayOutputStream(); try { err.write("The commandLine cannot be empty or not defined".getBytes(Charsets.UTF_8)); } catch (IOException e) { logger.error("Cannot write to error stream", e); } status.setErrorStream(err); return status; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/util/LinuxProcessUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.linux.util; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; import java.util.StringTokenizer; import javax.naming.OperationNotSupportedException; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.util.ProcessUtil; import org.eclipse.kura.core.util.SafeProcess; import org.eclipse.kura.system.SystemService; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of * {@link org.eclipse.kura.executor.CommandExecutorService} */ @Deprecated public class LinuxProcessUtil { private static final Logger logger = LoggerFactory.getLogger(LinuxProcessUtil.class); public static final String RETURNED_WITH_EXIT_VALUE = "{} returned with exit value: {}"; public static final String EXECUTING = "executing: {}"; public static final String PRIVILEGED_OPERATIONS_NOT_ALLOWED = "Privileged operations not allowed"; private static final String PS_COMMAND = "ps -ax"; private static final String PLATFORM_INTEL_EDISON = "intel-edison"; private static Boolean usingBusybox; protected LinuxProcessUtil() { // Empty private constructor } public static int start(String command, boolean wait, boolean background) throws OperationNotSupportedException, IOException { if (command.contains("sudo")) { throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED); } SafeProcess proc = null; try { logger.info(EXECUTING, command); proc = ProcessUtil.exec(command); if (wait) { waitFor(proc); logger.info(RETURNED_WITH_EXIT_VALUE, command, proc.exitValue()); if (proc.exitValue() > 0) { String stdout = getInputStreamAsString(proc.getInputStream()); String stderr = getInputStreamAsString(proc.getErrorStream()); logger.debug("stdout: {}", stdout); logger.debug("stderr: {}", stderr); } return proc.exitValue(); } else { return 0; } } finally { if (!background && proc != null) { ProcessUtil.destroy(proc); } } } public static int start(String command) throws OperationNotSupportedException, IOException { return start(command, true, false); } public static int start(String command, boolean wait) throws OperationNotSupportedException, IOException { return start(command, wait, false); } public static int start(String[] command, boolean wait) throws OperationNotSupportedException, IOException { StringBuilder cmdBuilder = new StringBuilder(); for (String cmd : command) { cmdBuilder.append(cmd).append(' '); } return start(cmdBuilder.toString(), wait); } public static int startBackground(String command, boolean wait) throws OperationNotSupportedException, IOException { return start(command, wait, true); } public static ProcessStats startWithStats(String command) throws OperationNotSupportedException, IOException { if (command.contains("sudo")) { throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED); } SafeProcess proc = null; logger.info(EXECUTING, command); proc = ProcessUtil.exec(command); try { int exitVal = proc.waitFor(); logger.debug(RETURNED_WITH_EXIT_VALUE, command, exitVal); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.error("error executing {} command", command, e); } return new ProcessStats(proc); } public static ProcessStats startWithStats(String[] command) throws OperationNotSupportedException, IOException { if (Arrays.asList(command).stream().anyMatch(s -> s.contains("sudo"))) { throw new OperationNotSupportedException(PRIVILEGED_OPERATIONS_NOT_ALLOWED); } SafeProcess proc = null; StringBuilder cmdBuilder = new StringBuilder(); for (String cmd : command) { cmdBuilder.append(cmd).append(' '); } logger.debug(EXECUTING, cmdBuilder); proc = ProcessUtil.exec(command); wairFor(proc, cmdBuilder); return new ProcessStats(proc); } public static int getPid(String command) throws IOException, InterruptedException { StringTokenizer st = null; String line = null; String pid = null; SafeProcess proc = null; BufferedReader br = null; try { if (command != null && !command.isEmpty()) { logger.trace("searching process list for {}", command); if (isUsingBusyBox()) { proc = ProcessUtil.exec("ps"); } else { proc = ProcessUtil.exec(PS_COMMAND); } proc.waitFor(); // get the output br = new BufferedReader(new InputStreamReader(proc.getInputStream())); while ((line = br.readLine()) != null) { st = new StringTokenizer(line); pid = st.nextToken(); st.nextElement(); st.nextElement(); st.nextElement(); // get the remainder of the line showing the command that // was issued line = line.substring(line.indexOf(st.nextToken())); // see if the line has our command if (line.indexOf(command) >= 0) { logger.trace("found pid {} for command: {}", pid, command); return Integer.parseInt(pid); } } } // return failure return -1; } finally { if (br != null) { br.close(); } if (proc != null) { ProcessUtil.destroy(proc); } } } public static int getPid(String command, String[] tokens) throws IOException, InterruptedException { StringTokenizer st = null; String line = null; String pid = null; SafeProcess proc = null; BufferedReader br = null; try { if (command != null && !command.isEmpty()) { logger.trace("searching process list for {}", command); if (isUsingBusyBox()) { proc = ProcessUtil.exec("ps"); } else { proc = ProcessUtil.exec(PS_COMMAND); } proc.waitFor(); // get the output br = new BufferedReader(new InputStreamReader(proc.getInputStream())); while ((line = br.readLine()) != null) { st = new StringTokenizer(line); pid = st.nextToken(); st.nextElement(); st.nextElement(); st.nextElement(); // get the remainder of the line showing the command that was issued line = line.substring(line.indexOf(st.nextToken())); // see if the line has our command if (line.indexOf(command) >= 0 && checkLine(line, tokens)) { logger.trace("found pid {} for command: {}", pid, command); return Integer.parseInt(pid); } } } return -1; } finally { if (br != null) { br.close(); } if (proc != null) { ProcessUtil.destroy(proc); } } } public static int getKuraPid() throws IOException { int pid = -1; File kuraPidFile = new File("/var/run/kura.pid"); if (kuraPidFile.exists()) { try (BufferedReader br = new BufferedReader(new FileReader(kuraPidFile))) { pid = Integer.parseInt(br.readLine()); } } return pid; } public static boolean stop(int pid) { return stop(pid, false); } public static boolean kill(int pid) { return stop(pid, true); } public static boolean killAll(String command) { boolean result = false; try { logger.info("attempting to kill process {}", command); result = (start("killall " + command) == 0); if (result) { logger.info("successfully killed process {}", command); } else { logger.warn("failed to kill process {}", command); } } catch (Exception e) { logger.warn("failed to kill process {}", command); } return result; } public static String getInputStreamAsString(InputStream stream) throws IOException { StringBuilder sb = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) { char[] cbuf = new char[1024]; int len; while ((len = br.read(cbuf)) > 0) { sb.append(cbuf, 0, len); } } return sb.toString(); } /** * This method takes a pid and returns a boolean that defines if the corresponding process is running or not in the * host system. * * @param pid * integer representing the process id that has to be verified. * @return true if the process in running in the system, false otherwise. * @throws IOException * if an I/O or execution error occurs */ public static boolean isProcessRunning(int pid) throws IOException { boolean isRunning = false; SafeProcess proc = null; BufferedReader br = null; try { logger.trace("searching process list for pid{}", pid); if (isUsingBusyBox()) { proc = ProcessUtil.exec("ps"); } else { proc = ProcessUtil.exec(PS_COMMAND); } proc.waitFor(); // get the output br = new BufferedReader(new InputStreamReader(proc.getInputStream())); String line = br.readLine(); // skip first line: PID TTY STAT TIME COMMAND while ((line = br.readLine()) != null) { if (parsePid(line) == pid) { isRunning = true; break; } } return isRunning; } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException(e); } finally { if (br != null) { br.close(); } if (proc != null) { ProcessUtil.destroy(proc); } } } /** * This method tries first to stop a process specified by the passed PID. If, aster this first step, the process is * still alive, the code invokes a kill operation. * * @param pid * An int representing the linux pid. * @throws KuraException * Thrown if one of the executed operations generate an exception. * @since {@link org.eclipse.kura.core.linux.util} 1.1.0 */ public static boolean stopAndKill(int pid) throws KuraException { try { if (pid >= 0) { logger.info("stopping pid={}", pid); boolean exists = stop(pid); if (!exists) { logger.warn("stopping pid={} has failed", pid); } else { exists = waitProcess(pid, 500, 5000); } if (exists) { logger.info("killing pid={}", pid); exists = kill(pid); if (!exists) { logger.warn("killing pid={} has failed", pid); } else { exists = waitProcess(pid, 500, 5000); } } if (exists) { logger.warn("Failed to stop process with pid {}", pid); return false; } } return true; } catch (Exception e) { throw KuraException.internalError(e); } } // // Private Methods // private static boolean isUsingBusyBox() { if (usingBusybox != null) { return usingBusybox; } final BundleContext ctx = FrameworkUtil.getBundle(LinuxProcessUtil.class).getBundleContext(); final ServiceReference systemServiceRef = ctx.getServiceReference(SystemService.class); if (systemServiceRef == null) { throw new IllegalStateException("Unable to find instance of: " + SystemService.class.getName()); } final SystemService service = ctx.getService(systemServiceRef); if (service == null) { throw new IllegalStateException("Unable to get instance of: " + SystemService.class.getName()); } try { usingBusybox = PLATFORM_INTEL_EDISON.equals(service.getPlatform()); } finally { ctx.ungetService(systemServiceRef); } return usingBusybox; } private static boolean stop(int pid, boolean kill) { boolean result = false; try { if (isProcessRunning(pid)) { StringBuilder cmd = new StringBuilder(); cmd.append("kill "); if (kill) { cmd.append("-9 "); } cmd.append(pid); if (kill) { logger.info("attempting to kill -9 pid {}", pid); } else { logger.info("attempting to kill pid {}", pid); } if (start(cmd.toString()) == 0) { logger.info("successfully killed pid {}", pid); result = true; } else { logger.warn("failed to kill pid {}", pid); } } } catch (Exception e) { logger.warn("failed to kill pid {}", pid); } return result; } private static boolean waitProcess(int pid, long poll, long timeout) { boolean exists = false; try { final long startTime = System.currentTimeMillis(); long now; do { Thread.sleep(poll); exists = isProcessRunning(pid); now = System.currentTimeMillis(); } while (exists && now - startTime < timeout); } catch (Exception e) { Thread.currentThread().interrupt(); logger.warn("Failed waiting for pid {} to exit - {}", pid, e); } return exists; } private static int parsePid(String line) { StringTokenizer st = new StringTokenizer(line); int processID = -1; try { processID = Integer.parseInt(st.nextToken()); } catch (NumberFormatException e) { logger.warn("getPid() :: NumberFormatException reading PID - {}", e); } return processID; } private static void waitFor(SafeProcess proc) { try { proc.waitFor(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.warn("Interrupted exception - ", e); } } private static void wairFor(SafeProcess proc, StringBuilder cmdBuilder) { try { int exitVal = proc.waitFor(); logger.debug(RETURNED_WITH_EXIT_VALUE, cmdBuilder, exitVal); } catch (InterruptedException e) { Thread.currentThread().interrupt(); logger.error("error executing {} command", cmdBuilder, e); } } private static boolean checkLine(String line, String[] tokens) { boolean allTokensPresent = true; for (String token : tokens) { if (!line.contains(token)) { allTokensPresent = false; break; } } return allTokensPresent; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/linux/util/ProcessStats.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.linux.util; import java.io.InputStream; import java.io.OutputStream; import org.eclipse.kura.core.util.SafeProcess; /** * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 */ @Deprecated public class ProcessStats { private final SafeProcess process; public ProcessStats(SafeProcess proc) { this.process = proc; } public SafeProcess getProcess() { return this.process; } public OutputStream getOutputStream() { return this.process.getOutputStream(); } public InputStream getInputStream() { return this.process.getInputStream(); } public InputStream getErrorStream() { return this.process.getErrorStream(); } public int getReturnValue() { return this.process.exitValue(); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/ConnectionSslOptions.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import java.util.Arrays; public class ConnectionSslOptions { private final SslManagerServiceOptions sslManagerOpts; private String protocol; private String ciphers; private String trustStore; private String keyStore; private char[] keyStorePassword; private String alias; private boolean hostnameVerification; public ConnectionSslOptions(SslManagerServiceOptions sslManagerOpts) { this.sslManagerOpts = sslManagerOpts; } public SslManagerServiceOptions getSslManagerOpts() { return this.sslManagerOpts; } public String getProtocol() { return this.protocol; } public void setProtocol(String protocol) { if (protocol == null || "".equals(protocol.trim())) { this.protocol = this.sslManagerOpts.getSslProtocol(); } else { this.protocol = protocol; } } public String getCiphers() { return this.ciphers; } public void setCiphers(String ciphers) { if (ciphers == null || "".equals(ciphers.trim())) { this.ciphers = this.sslManagerOpts.getSslCiphers(); } else { this.ciphers = ciphers; } } public String getTrustStore() { return this.trustStore; } public void setTrustStore(String trustStore) { this.trustStore = trustStore; } public String getKeyStore() { return this.keyStore; } public void setKeyStore(String keyStore) { this.keyStore = keyStore; } public char[] getKeyStorePassword() { return this.keyStorePassword; } public void setKeyStorePassword(char[] keyStorePassword) { this.keyStorePassword = keyStorePassword; } public String getAlias() { return this.alias; } public void setAlias(String alias) { this.alias = alias; } public boolean getHostnameVerification() { return this.hostnameVerification; } public void setHostnameVerification(boolean hostnameVerification) { this.hostnameVerification = hostnameVerification; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.alias == null ? 0 : this.alias.hashCode()); result = prime * result + (this.ciphers == null ? 0 : this.ciphers.hashCode()); result = prime * result + (this.hostnameVerification ? 1231 : 1237); result = prime * result + (this.keyStore == null ? 0 : this.keyStore.hashCode()); result = prime * result + Arrays.hashCode(this.keyStorePassword); result = prime * result + (this.protocol == null ? 0 : this.protocol.hashCode()); result = prime * result + (this.sslManagerOpts == null ? 0 : this.sslManagerOpts.hashCode()); result = prime * result + (this.trustStore == null ? 0 : this.trustStore.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof ConnectionSslOptions)) { return false; } ConnectionSslOptions other = (ConnectionSslOptions) obj; if (this.alias == null) { if (other.alias != null) { return false; } } else if (!this.alias.equals(other.alias)) { return false; } if (this.ciphers == null) { if (other.ciphers != null) { return false; } } else if (!this.ciphers.equals(other.ciphers)) { return false; } if (this.hostnameVerification != other.hostnameVerification) { return false; } if (this.keyStore == null) { if (other.keyStore != null) { return false; } } else if (!this.keyStore.equals(other.keyStore)) { return false; } if (!Arrays.equals(this.keyStorePassword, other.keyStorePassword)) { return false; } if (this.protocol == null) { if (other.protocol != null) { return false; } } else if (!this.protocol.equals(other.protocol)) { return false; } if (this.sslManagerOpts == null) { if (other.sslManagerOpts != null) { return false; } } else if (!this.sslManagerOpts.equals(other.sslManagerOpts)) { return false; } if (this.trustStore == null) { if (other.trustStore != null) { return false; } } else if (!this.trustStore.equals(other.trustStore)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SSLContextSPIWrapper.java ================================================ /******************************************************************************* * Copyright (c) 2019, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import java.security.KeyManagementException; import java.security.SecureRandom; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContextSpi; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; public class SSLContextSPIWrapper extends SSLContextSpi { private final SSLContext wrapped; private final SSLSocketFactory factory; public SSLContextSPIWrapper(final SSLContext wrapped, final SSLSocketFactory factory) { this.wrapped = wrapped; this.factory = factory; } @Override protected SSLEngine engineCreateSSLEngine() { return this.wrapped.createSSLEngine(); } @Override protected SSLEngine engineCreateSSLEngine(final String arg0, final int arg1) { return this.wrapped.createSSLEngine(arg0, arg1); } @Override protected SSLSessionContext engineGetClientSessionContext() { return this.wrapped.getClientSessionContext(); } @Override protected SSLSessionContext engineGetServerSessionContext() { return this.wrapped.getServerSessionContext(); } @Override protected SSLServerSocketFactory engineGetServerSocketFactory() { return this.wrapped.getServerSocketFactory(); } @Override protected SSLSocketFactory engineGetSocketFactory() { return this.factory; } @Override protected void engineInit(KeyManager[] arg0, TrustManager[] arg1, SecureRandom arg2) throws KeyManagementException { this.wrapped.init(arg0, arg1, arg2); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SSLSocketFactoryWrapper.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Wrapper over the SSLSocketFactory which enforces HTTPS style hostname validation on the returned sockets. * http://stackoverflow.com/questions/18139448/how-should-i-do-hostname-validation-when-using-jsse */ public class SSLSocketFactoryWrapper extends SSLSocketFactory { private static final Logger logger = LoggerFactory.getLogger(SSLSocketFactoryWrapper.class); private final String ciphers; private final Boolean hostnameVerification; private final SSLSocketFactory sslsf; public SSLSocketFactoryWrapper(SSLSocketFactory sslsf, String ciphers, Boolean hnVerify) { this.sslsf = sslsf; this.ciphers = ciphers; this.hostnameVerification = hnVerify; } @Override public String[] getDefaultCipherSuites() { return this.sslsf.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return this.sslsf.getSupportedCipherSuites(); } @Override public Socket createSocket() throws IOException { Socket socket = this.sslsf.createSocket(); updateSSLParameters(socket); return socket; } @Override public Socket createSocket(InetAddress host, int port) throws IOException { Socket socket = this.sslsf.createSocket(host, port); updateSSLParameters(socket); return socket; } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { Socket socket = this.sslsf.createSocket(host, port, localHost, localPort); updateSSLParameters(socket); return socket; } @Override public Socket createSocket(String host, int port) throws IOException { Socket socket = this.sslsf.createSocket(host, port); updateSSLParameters(socket); return socket; } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { Socket socket = this.sslsf.createSocket(address, port, address, localPort); updateSSLParameters(socket); return socket; } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { Socket socket = this.sslsf.createSocket(s, host, port, autoClose); updateSSLParameters(socket); return socket; } private void updateSSLParameters(Socket socket) throws SocketException { if (socket instanceof SSLSocket) { SSLSocket sslSocket = (SSLSocket) socket; SSLParameters sslParams = sslSocket.getSSLParameters(); // Do not send an SSL-2.0-compatible Client Hello. ArrayList protocols = new ArrayList<>(Arrays.asList(sslParams.getProtocols())); protocols.remove("SSLv2Hello"); sslParams.setProtocols(protocols.toArray(new String[protocols.size()])); // enable server verification if (this.hostnameVerification) { sslParams.setEndpointIdentificationAlgorithm("HTTPS"); logger.info("SSL Endpoint Identification enabled."); } // Adjust the supported ciphers. if (this.ciphers != null && !this.ciphers.isEmpty()) { String[] arrCiphers = this.ciphers.split(","); ArrayList lsCiphers = new ArrayList<>(); for (String cipher : arrCiphers) { lsCiphers.add(cipher.trim()); } sslParams.setCipherSuites(lsCiphers.toArray(new String[lsCiphers.size()])); } // update the socket parameters sslSocket.setSSLParameters(sslParams); // Disable the Nagle algorithm. socket.setTcpNoDelay(true); } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import static java.util.Objects.isNull; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStore.TrustedCertificateEntry; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.PrivateKey; import java.security.UnrecoverableEntryException; import java.security.cert.CertPathBuilder; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXParameters; import java.security.cert.PKIXRevocationChecker; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import javax.net.ssl.CertPathTrustManagerParameters; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509KeyManager; import javax.net.ssl.X509TrustManager; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraRuntimeException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.ssl.SslManagerServiceOptions.RevocationCheckMode; import org.eclipse.kura.security.keystore.KeystoreChangedEvent; import org.eclipse.kura.security.keystore.KeystoreService; import org.eclipse.kura.ssl.SslManagerService; import org.eclipse.kura.ssl.SslServiceListener; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Modified; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import org.osgi.service.event.Event; import org.osgi.service.event.EventConstants; import org.osgi.service.event.EventHandler; import org.osgi.service.metatype.annotations.Designate; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Component(name = "org.eclipse.kura.ssl.SslManagerService", // configurationPolicy = ConfigurationPolicy.REQUIRE, // immediate = true, // property = { // "kura.ui.factory.hide=true", // "kura.ui.service.hide=true", // EventConstants.EVENT_TOPIC + "=" + KeystoreChangedEvent.EVENT_TOPIC }) @Designate(ocd = SslManagerServiceOCD.class, factory = true) public class SslManagerServiceImpl implements SslManagerService, ConfigurableComponent, EventHandler { private static final Logger logger = LoggerFactory.getLogger(SslManagerServiceImpl.class); private final SslServiceListeners sslServiceListeners; private SslManagerServiceOptions options; private KeystoreService keystoreService; private KeystoreService truststoreKeystoreService; private Map sslContexts; private Optional keystoreServicePid = Optional.empty(); private Optional truststoreKeystoreServicePid = Optional.empty(); // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL) public void setKeystoreService(KeystoreService keystoreService, final Map properties) { this.keystoreService = keystoreService; this.keystoreServicePid = Optional.of((String) properties.get(ConfigurationService.KURA_SERVICE_PID)); this.clearSslContexCache(); if (this.sslServiceListeners != null) { // Notify listeners that service has been updated this.sslServiceListeners.onConfigurationUpdated(); } } public void unsetKeystoreService(KeystoreService keystoreService) { if (this.keystoreService == keystoreService) { this.keystoreService = null; this.keystoreServicePid = Optional.empty(); this.clearSslContexCache(); if (this.sslServiceListeners != null) { // Notify listeners that service has been updated this.sslServiceListeners.onConfigurationUpdated(); } } } @Reference(policy = ReferencePolicy.DYNAMIC, cardinality = ReferenceCardinality.OPTIONAL) public void setTruststoreKeystoreService(KeystoreService keystoreService, final Map properties) { this.truststoreKeystoreService = keystoreService; this.truststoreKeystoreServicePid = Optional.of((String) properties.get(ConfigurationService.KURA_SERVICE_PID)); this.clearSslContexCache(); if (this.sslServiceListeners != null) { // Notify listeners that service has been updated this.sslServiceListeners.onConfigurationUpdated(); } } public void unsetTruststoreKeystoreService(KeystoreService keystoreService) { if (this.truststoreKeystoreService == keystoreService) { this.truststoreKeystoreService = null; this.truststoreKeystoreServicePid = Optional.empty(); this.clearSslContexCache(); if (this.sslServiceListeners != null) { // Notify listeners that service has been updated this.sslServiceListeners.onConfigurationUpdated(); } } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- @Activate public SslManagerServiceImpl(ComponentContext componentContext, Map properties) { logger.info("activate..."); this.options = new SslManagerServiceOptions(properties); this.sslContexts = new ConcurrentHashMap<>(); ServiceTracker listenersTracker = new ServiceTracker<>( componentContext.getBundleContext(), SslServiceListener.class, null); // Deferred open of tracker to prevent // java.lang.Exception: Recursive invocation of // ServiceFactory.getService // on ProSyst this.sslServiceListeners = new SslServiceListeners(listenersTracker); } @Modified public void updated(Map properties) { logger.info("updated..."); this.options = new SslManagerServiceOptions(properties); this.sslContexts = new ConcurrentHashMap<>(); // Notify listeners that service has been updated this.sslServiceListeners.onConfigurationUpdated(); } @Deactivate protected void deactivate(ComponentContext componentContext) { logger.info("deactivate..."); this.sslServiceListeners.close(); } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public SSLContext getSSLContext() throws GeneralSecurityException, IOException { return getSSLContext(""); } @Override public SSLContext getSSLContext(String keyAlias) throws GeneralSecurityException, IOException { String protocol = this.options.getSslProtocol(); String ciphers = this.options.getSslCiphers(); boolean hostnameVerifcation = this.options.isSslHostnameVerification(); return getSSLContext(protocol, ciphers, null, null, null, keyAlias, hostnameVerifcation); } private SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore, char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException { return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias, this.options.isSslHostnameVerification()); } private SSLContext getSSLContext(String protocol, String ciphers, String trustStore, String keyStore, char[] keyStorePassword, String keyAlias, boolean hostnameVerification) throws GeneralSecurityException, IOException { ConnectionSslOptions connSslOpts = new ConnectionSslOptions(this.options); connSslOpts.setProtocol(protocol); connSslOpts.setCiphers(ciphers); connSslOpts.setTrustStore(trustStore); connSslOpts.setKeyStore(keyStore); connSslOpts.setKeyStorePassword(keyStorePassword); connSslOpts.setAlias(keyAlias); connSslOpts.setHostnameVerification(hostnameVerification); return getSSLContextInternal(connSslOpts); } @Override public SSLSocketFactory getSSLSocketFactory() throws GeneralSecurityException, IOException { return getSSLContext().getSocketFactory(); } @Override public SSLSocketFactory getSSLSocketFactory(String keyAlias) throws GeneralSecurityException, IOException { return getSSLContext(keyAlias).getSocketFactory(); } @Override public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore, char[] keyStorePassword, String keyAlias) throws GeneralSecurityException, IOException { return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias).getSocketFactory(); } @Override public SSLSocketFactory getSSLSocketFactory(String protocol, String ciphers, String trustStore, String keyStore, char[] keyStorePassword, String keyAlias, boolean hostnameVerification) throws GeneralSecurityException, IOException { return getSSLContext(protocol, ciphers, trustStore, keyStore, keyStorePassword, keyAlias, hostnameVerification) .getSocketFactory(); } @Override public X509Certificate[] getTrustCertificates() throws GeneralSecurityException, IOException { X509Certificate[] cacerts = null; TrustManager[] tms = getTrustManagers(); for (TrustManager tm : tms) { if (tm instanceof X509TrustManager) { X509TrustManager x509tm = (X509TrustManager) tm; cacerts = x509tm.getAcceptedIssuers(); break; } } return cacerts; } @Override public void installTrustCertificate(String alias, X509Certificate x509crt) throws GeneralSecurityException, IOException { if (isNull(this.keystoreService)) { throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review } TrustedCertificateEntry trustedCertificateEntry = new TrustedCertificateEntry(x509crt); try { this.keystoreService.setEntry(alias, trustedCertificateEntry); } catch (KuraException e) { throw new IOException(e); } } @Override public void deleteTrustCertificate(String alias) throws GeneralSecurityException, IOException { try { this.keystoreService.deleteEntry(alias); } catch (KuraException e) { throw new IOException(e); } } @Override public void installPrivateKey(String alias, PrivateKey privateKey, char[] password, Certificate[] publicCerts) throws GeneralSecurityException, IOException { if (isNull(this.keystoreService)) { throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review } PrivateKeyEntry privateKeyEntry = new PrivateKeyEntry(privateKey, publicCerts); try { this.keystoreService.setEntry(alias, privateKeyEntry); } catch (KuraException e) { throw new IOException(e); } } private KeyStore loadKeystore(String keyStore, char[] keyStorePassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); try (InputStream tsReadStream = new FileInputStream(keyStore);) { ks.load(tsReadStream, keyStorePassword); } return ks; } // ---------------------------------------------------------------- // // Private methods // // ---------------------------------------------------------------- private SSLContext getSSLContextInternal(ConnectionSslOptions options) throws GeneralSecurityException, IOException { // Only create a new SSLSocketFactory instance if the configuration has // changed or // for a new alias. // This allows for SSL Context Resumption and abbreviated SSL handshake // in case of reconnects to the same host. SSLContext context = this.sslContexts.get(options); if (context == null) { logger.info("Creating a new SSLSocketFactory instance"); TrustManager[] tms = null; KeyManager[] kms = null; if (isNull(options.getTrustStore()) && isNull(options.getKeyStorePassword())) { tms = getTrustManagers(); kms = getKeyManagers(); } else { tms = getTrustManagers(options.getTrustStore(), options.getKeyStorePassword()); kms = getKeyManagers(options.getKeyStore(), options.getKeyStorePassword(), options.getAlias()); } context = createSSLContext(options.getProtocol(), options.getCiphers(), kms, tms, options.getHostnameVerification()); this.sslContexts.put(options, context); } return context; } private static SSLContext createSSLContext(String protocol, String ciphers, KeyManager[] kms, TrustManager[] tms, boolean hostnameVerification) throws NoSuchAlgorithmException, KeyManagementException { // inits the SSL context SSLContext sslCtx; if (protocol == null || protocol.isEmpty()) { sslCtx = SSLContext.getDefault(); } else { sslCtx = SSLContext.getInstance(protocol); sslCtx.init(kms, tms, null); } // get the SSLSocketFactory final SSLSocketFactory sslSocketFactory = sslCtx.getSocketFactory(); final SSLSocketFactoryWrapper socketFactoryWrapper = new SSLSocketFactoryWrapper(sslSocketFactory, ciphers, hostnameVerification); // wrap it return new SSLContext(new SSLContextSPIWrapper(sslCtx, socketFactoryWrapper), sslCtx.getProvider(), sslCtx.getProtocol()) { }; } private TrustManager[] getTrustManagers() throws GeneralSecurityException, IOException { TrustManager[] result = new TrustManager[0]; TrustManagerFactory tmf = null; final KeystoreService ks; if (this.truststoreKeystoreService != null) { ks = truststoreKeystoreService; } else if (this.keystoreService != null) { ks = keystoreService; } else { return result; } try { KeyStore ts = ks.getKeyStore(); tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); initTrustManagerFactory(tmf, ts); result = tmf.getTrustManagers(); } catch (KuraException e) { throw new IOException(e); } return result; } private TrustManager[] getTrustManagers(String trustStore, char[] keyStorePassword) throws IOException, GeneralSecurityException { TrustManager[] result = new TrustManager[0]; TrustManagerFactory tmf = null; if (trustStore != null) { // Load the configured the Trust Store File fTrustStore = new File(trustStore); if (fTrustStore.exists()) { KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType()); InputStream tsReadStream = new FileInputStream(trustStore); ts.load(tsReadStream, keyStorePassword); tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); initTrustManagerFactory(tmf, ts); result = tmf.getTrustManagers(); tsReadStream.close(); } } return result; } private void initTrustManagerFactory(final TrustManagerFactory trustManagerFactory, final KeyStore keyStore) throws KeyStoreException, InvalidAlgorithmParameterException, NoSuchAlgorithmException { if (!this.options.isSslRevocationCheckEnabled()) { trustManagerFactory.init(keyStore); return; } List certStores; try { certStores = Collections.singletonList(keystoreService.getCRLStore()); } catch (final Exception e) { logger.warn("Failed to get CRL store", e); certStores = Collections.emptyList(); } final EnumSet checkerOptions; final RevocationCheckMode revocationCheckMode = options.getRevocationCheckMode(); if (revocationCheckMode == RevocationCheckMode.CRL_ONLY) { checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS, PKIXRevocationChecker.Option.NO_FALLBACK); } else if (revocationCheckMode == RevocationCheckMode.PREFER_CRL) { checkerOptions = EnumSet.of(PKIXRevocationChecker.Option.PREFER_CRLS); } else { checkerOptions = EnumSet.noneOf(PKIXRevocationChecker.Option.class); } if (this.options.isSslRevocationSoftFail()) { checkerOptions.add(PKIXRevocationChecker.Option.SOFT_FAIL); } final CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX"); final PKIXRevocationChecker revocationChecker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker(); revocationChecker.setOptions(checkerOptions); PKIXParameters pkixParams = new PKIXBuilderParameters(keyStore, new X509CertSelector()); pkixParams.setRevocationEnabled(true); pkixParams.setCertStores(certStores); pkixParams.addCertPathChecker(revocationChecker); trustManagerFactory.init(new CertPathTrustManagerParameters(pkixParams)); } private KeyManager[] getKeyManagers() throws IOException { if (isNull(this.keystoreService)) { throw new KuraRuntimeException(KuraErrorCode.INTERNAL_ERROR); // TO DO:review } try { return this.keystoreService.getKeyManagers(KeyManagerFactory.getDefaultAlgorithm()) .toArray(new KeyManager[0]); // TO DO: it was possible to load a keystore based on Alias. Now it is not possible. } catch (KuraException e) { throw new IOException(e); } } private KeyManager[] getKeyManagers(String keyStore, char[] keyStorePassword, String keyAlias) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableEntryException { KeyStore ks = getKeyStore(keyStore, keyStorePassword, keyAlias); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, keyStorePassword); final List matching = Arrays.stream(kmf.getKeyManagers()) .filter(m -> m instanceof X509KeyManager && ((X509KeyManager) m).getCertificateChain(keyAlias) != null) .map(k -> new SingleAliasX509KeyManager(keyAlias, (X509KeyManager) k)).collect(Collectors.toList()); return matching.toArray(new KeyManager[matching.size()]); } private KeyStore getKeyStore(String keyStore, char[] keyStorePassword, String keyAlias) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { // Load the configured the Key Store File fKeyStore = new File(keyStore); if (!fKeyStore.exists() || !isKeyStoreAccessible(keyStore, keyStorePassword)) { logger.warn("The referenced keystore does not exist or is not accessible"); throw new KeyStoreException("The referenced keystore does not exist or is not accessible"); } try (InputStream ksReadStream = new FileInputStream(keyStore);) { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(ksReadStream, keyStorePassword); // if we have an alias, then build KeyStore with such key if (ks.containsAlias(keyAlias) && ks.isKeyEntry(keyAlias)) { return ks; } return ks; } } private boolean isKeyStoreAccessible(String location, char[] password) { try { loadKeystore(location, password); return true; } catch (Exception e) { return false; } } private class SingleAliasX509KeyManager implements X509KeyManager { private final String alias; private final X509KeyManager wrapped; public SingleAliasX509KeyManager(final String alias, final X509KeyManager wrapped) { this.alias = alias; this.wrapped = wrapped; } @Override public String[] getClientAliases(String keyType, Principal[] issuers) { return new String[] { this.alias }; } @Override public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) { return this.alias; } @Override public String[] getServerAliases(String keyType, Principal[] issuers) { return new String[] { this.alias }; } @Override public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) { return this.alias; } @Override public X509Certificate[] getCertificateChain(String alias) { if (this.alias.equals(alias)) { return this.wrapped.getCertificateChain(alias); } return new X509Certificate[0]; } @Override public PrivateKey getPrivateKey(String alias) { if (this.alias.equals(alias)) { return this.wrapped.getPrivateKey(alias); } return null; } } @Override public void handleEvent(final Event event) { if (!(event instanceof KeystoreChangedEvent)) { return; } final KeystoreChangedEvent keystoreChangedEvent = (KeystoreChangedEvent) event; final Optional eventPid = Optional.of(keystoreChangedEvent.getSenderPid()); if (this.keystoreServicePid.equals(eventPid) || this.truststoreKeystoreServicePid.equals(eventPid)) { this.clearSslContexCache(); this.sslServiceListeners.onConfigurationUpdated(); } } private void clearSslContexCache() { if (sslContexts != null) { this.sslContexts.clear(); } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceOCD.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.Icon; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.osgi.service.metatype.annotations.Option; @SuppressWarnings("checkstyle:MethodName") @ObjectClassDefinition(id = "org.eclipse.kura.ssl.SslManagerService", // name = "SslManagerService", // description = "The SslManagerService is responsible to manage the configuration of the SSL connections.", // icon = @Icon(resource = "SslManagerService", size = 32) // ) public interface SslManagerServiceOCD { @AttributeDefinition(name = "ssl.default.protocol", // required = false, // defaultValue = "TLSv1.2", // description = "The protocol to use to initialize the SSLContext. " + "If not specified, the default JVM SSL Context will be used.") String ssl_default_protocol(); @AttributeDefinition(name = "ssl.hostname.verification", // required = false, // defaultValue = "true", // description = "Enable or disable hostname verification.") Boolean ssl_hostname_verification(); @AttributeDefinition(name = "Keystore Target Filter", // defaultValue = "(kura.service.pid=changeme)", // description = "Specifies, as an OSGi target filter, " + "the pid of the KeystoreService used to manage the SSL key store.") String KeystoreService_target(); @AttributeDefinition(name = "Truststore Target Filter", // defaultValue = "(kura.service.pid=changeme)", // description = "Specifies, as an OSGi target filter, " + "the pid of the KeystoreService used to manage the SSL trust Store." + " If the target service cannot be found, " + "the service configured with the Keystore Target Filter parameter will be used as truststore.") String TruststoreKeystoreService_target(); @AttributeDefinition(name = "ssl.default.cipherSuites", // required = false, // description = "Comma-separated list of allowed ciphers." + " If not specifed, all Java VM ciphers will be allowed.") String ssl_default_cipherSuites(); @AttributeDefinition(name = "Revocation Check Enabled", // required = false, // defaultValue = "false", // description = "If enabled, " + "the revocation status of server certificates will be ckeched during TLS handshake. " + "If a revoked certificate is detected, handshake will fail. " + "The revocation status will be checked using OCSP, CRLDP or the CRLs cached by the attached KeystoreService instance, " + "depending on the value of the Revocation Check Mode parameter. " + "If not enabled, revocation ckeck will not be performed.") Boolean ssl_revocation_check_enabled(); @AttributeDefinition(name = "Revocation Check Mode", // defaultValue = "PREFER_OCSP", // description = "Specifies the mode for performing revocation check. " + "This parameter is ignored if Revocation Check Enabled is set to false.", // options = { @Option(label = "Use OCSP first and then KeystoreService CRLs and CRLDP", value = "PREFER_OCSP"), // @Option(label = "Use KeystoreService CRLs and CRLDP first and then OCSP", value = "PREFER_CRL"), // @Option(label = "Use only KeystoreService CRLs and CRLDP", value = "CRL_ONLY") // }) String ssl_revocation_mode(); @AttributeDefinition(name = "Revocation Soft-fail Enabled", // defaultValue = "false", // description = "Specifies whether the revocation soft fail is enabled or not." // + " If it is not enabled and the gateway is not able to determine the revocation status of a server certificate," + " for example due to a network error, the certificate will be rejected." + " This parameter is ignored if Revocation Check Enabled is set to false.") Boolean ssl_revocation_soft_fail(); } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslManagerServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import static java.util.Objects.isNull; import java.util.Map; import org.eclipse.kura.util.configuration.Property; public class SslManagerServiceOptions { public enum RevocationCheckMode { PREFER_OCSP, PREFER_CRL, CRL_ONLY } public static final String PROP_PROTOCOL = "ssl.default.protocol"; public static final String PROP_CIPHERS = "ssl.default.cipherSuites"; public static final String PROP_HN_VERIFY = "ssl.hostname.verification"; public static final Boolean PROP_DEFAULT_HN_VERIFY = true; public static final String PROP_DEFAULT_TRUST_PASSWORD = "changeit"; private static final Property SELECTED_SSL_PROTOCOL = new Property<>(PROP_PROTOCOL, ""); private static final Property SELECTED_SSL_CIPHERS = new Property<>(PROP_CIPHERS, ""); private static final Property SELECTED_SSL_HN_VERIFICATION = new Property<>(PROP_HN_VERIFY, PROP_DEFAULT_HN_VERIFY); private static final Property SSL_REVOCATION_CHECK_ENABLED = new Property<>("ssl.revocation.check.enabled", false); private static final Property SSL_REVOCATION_SOFT_FAIL = new Property<>("ssl.revocation.soft.fail", false); private static final Property SSL_REVOCATION_MODE = new Property<>("ssl.revocation.mode", RevocationCheckMode.PREFER_OCSP.name()); private final Map properties; private final String sslProtocol; private final String sslCiphers; private final boolean sslHNVerification; private final boolean sslRevocationCheckEnabled; private final RevocationCheckMode sslRevocationMode; private final boolean sslRevocationSoftFail; public SslManagerServiceOptions(Map properties) { if (isNull(properties)) { throw new IllegalArgumentException("SSL Options cannot be null!"); } this.properties = properties; this.sslProtocol = SELECTED_SSL_PROTOCOL.get(properties).trim(); this.sslCiphers = SELECTED_SSL_CIPHERS.get(properties).trim(); this.sslHNVerification = SELECTED_SSL_HN_VERIFICATION.get(properties); this.sslRevocationCheckEnabled = SSL_REVOCATION_CHECK_ENABLED.get(properties); this.sslRevocationMode = RevocationCheckMode.valueOf(SSL_REVOCATION_MODE.get(properties)); this.sslRevocationSoftFail = SSL_REVOCATION_SOFT_FAIL.get(properties); } public Map getConfigurationProperties() { return this.properties; } /** * Returns the ssl.default.protocol. * * @return */ public String getSslProtocol() { return this.sslProtocol; } /** * Returns the ssl.default.trustStore. * * @return */ public String getSslCiphers() { return this.sslCiphers; } /** * Returns the ssl.hostname.verification * * @return */ public Boolean isSslHostnameVerification() { return this.sslHNVerification; } public boolean isSslRevocationCheckEnabled() { return sslRevocationCheckEnabled; } public RevocationCheckMode getRevocationCheckMode() { return sslRevocationMode; } public boolean isSslRevocationSoftFail() { return sslRevocationSoftFail; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.properties == null ? 0 : this.properties.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof SslManagerServiceOptions)) { return false; } SslManagerServiceOptions other = (SslManagerServiceOptions) obj; if (this.properties == null) { if (other.properties != null) { return false; } } else if (!this.properties.equals(other.properties)) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/ssl/SslServiceListeners.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.ssl; import org.eclipse.kura.ssl.SslServiceListener; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; class SslServiceListeners implements SslServiceListener { private static final Logger logger = LoggerFactory.getLogger(SslServiceListeners.class); private final ServiceTracker listenersTracker; public SslServiceListeners(ServiceTracker listenersTracker) { super(); this.listenersTracker = listenersTracker; } @Override public void onConfigurationUpdated() { openOnce(); Object[] listeners = this.listenersTracker.getServices(); if (listeners != null && listeners.length != 0) { for (Object listener : listeners) { try { ((SslServiceListener) listener).onConfigurationUpdated(); } catch (Throwable t) { logger.error("Unexpected Throwable", t); } } } } public synchronized void close() { if (this.listenersTracker.getTrackingCount() != -1) { this.listenersTracker.close(); } } private synchronized void openOnce() { if (this.listenersTracker.getTrackingCount() == -1) { this.listenersTracker.open(); } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/GZipUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; public class GZipUtil { private GZipUtil() { } public static boolean isCompressed(byte[] bytes) { if (bytes == null || bytes.length < 2) { return false; } else { return bytes[0] == (byte) GZIPInputStream.GZIP_MAGIC && bytes[1] == (byte) (GZIPInputStream.GZIP_MAGIC >> 8); } } public static byte[] compress(byte[] source) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { GZIPOutputStream gzipos = new GZIPOutputStream(baos); gzipos.write(source); gzipos.close(); return baos.toByteArray(); } } public static byte[] decompress(byte[] source) throws IOException { try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayInputStream bais = new ByteArrayInputStream(source); GZIPInputStream gzipis = new GZIPInputStream(bais);) { int n; final int maxBuf = 1024; byte[] buf = new byte[maxBuf]; while ((n = gzipis.read(buf, 0, maxBuf)) != -1) { baos.write(buf, 0, n); } return baos.toByteArray(); } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/IOUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.util; import static java.lang.Thread.currentThread; import java.io.IOException; import java.net.URL; import org.apache.commons.io.IOUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; /** * A few basic IO helper methods */ public final class IOUtil { private IOUtil() { } /** * Reads a resource fully and returns it as a string. * * @param resourceName * the name of the resource * @return the content as string, or {@code null if the resource could not be found} * @throws IOException * in case there is a resource but it cannot be read */ public static String readResource(final String resourceName) throws IOException { return readResource(currentThread().getContextClassLoader().getResource(resourceName)); } /** * Reads a resource fully and returns it as a string. * * @param ctx * the bundle context to use for locating the resource * @param resourceName * the name of the resource * @return the content as string, or {@code null if the resource could not be found} * @throws IOException * in case there is a resource but it cannot be read */ public static String readResource(BundleContext ctx, String resourceName) throws IOException { return readResource(ctx.getBundle().getResource(resourceName)); } /** * Reads a resource fully and returns it as a string. * * @param bundle * the bundle to use for getting the bundle context * @param resourceName * the name of the resource * @return the content as string, or {@code null if the resource could not be found} * @throws IOException * in case there is a resource but it cannot be read */ public static String readResource(Bundle bundle, String resourceName) throws IOException { return readResource(bundle.getResource(resourceName)); } /** * Reads a resource fully and returns it as a string. * * @param resourceUrl * the URL to read the resource from, may be {@code null} * @return the content as string, or {@code null if the resource could not be found} * @throws IOException * in case there is a resource but it cannot be read */ public static String readResource(URL resourceUrl) throws IOException { if (resourceUrl == null) { return null; } return IOUtils.toString(resourceUrl); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/NamedThreadFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; public class NamedThreadFactory implements ThreadFactory { public NamedThreadFactory() { } @Override public Thread newThread(Runnable r) { Thread t = Executors.defaultThreadFactory().newThread(r); String className = r.getClass().getSimpleName(); t.setName(className); return t; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/NetUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.net.InetAddress; import java.net.NetworkInterface; import java.util.Enumeration; import java.util.StringJoiner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class NetUtil { private static final String MAC_IS_INVALID_MESSAGE = "mac is invalid: "; private static final Logger logger = LoggerFactory.getLogger(NetUtil.class); private NetUtil() { } public static String hardwareAddressToString(byte[] macAddress) { if (macAddress == null) { return "N/A"; } if (macAddress.length != 6) { throw new IllegalArgumentException("macAddress is invalid"); } StringJoiner sj = new StringJoiner(":"); for (byte item : macAddress) { sj.add(String.format("%02X", item)); } return sj.toString(); } public static byte[] hardwareAddressToBytes(String macAddress) { if (macAddress == null || macAddress.isEmpty()) { return new byte[] { 0, 0, 0, 0, 0, 0 }; } String[] items = macAddress.split("\\:"); if (items.length != 6) { throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress); } byte[] bytes = new byte[6]; for (int i = 0; i < 6; i++) { String item = items[i]; if (item.isEmpty() || item.length() > 2) { throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress); } try { bytes[i] = (byte) Integer.parseInt(items[i], 16); } catch (NumberFormatException e) { throw new IllegalArgumentException(MAC_IS_INVALID_MESSAGE + macAddress, e); } } return bytes; } public static String getPrimaryMacAddress() { NetworkInterface firstInterface = null; Enumeration nifs = null; try { // look for eth0 or en0 first nifs = NetworkInterface.getNetworkInterfaces(); if (nifs != null) { while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); if ("eth0".equals(nif.getName()) || "en0".equals(nif.getName())) { return hardwareAddressToString(nif.getHardwareAddress()); } } } // if not found yet, look for the first active ethernet interface nifs = NetworkInterface.getNetworkInterfaces(); if (nifs != null) { while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); if (!nif.isVirtual() && nif.getHardwareAddress() != null) { firstInterface = nif; if (nif.getName().startsWith("eth") || nif.getName().startsWith("en")) { return hardwareAddressToString(nif.getHardwareAddress()); } } } } if (firstInterface != null) { return hardwareAddressToString(firstInterface.getHardwareAddress()); } } catch (Exception e) { logger.warn("Exception while getting current IP", e); } return null; } public static InetAddress getCurrentInetAddress() { try { Enumeration nifs = NetworkInterface.getNetworkInterfaces(); if (nifs != null) { while (nifs.hasMoreElements()) { NetworkInterface nif = nifs.nextElement(); if (!nif.isLoopback() && nif.isUp() && !nif.isVirtual() && nif.getHardwareAddress() != null) { Enumeration nadrs = nif.getInetAddresses(); while (nadrs.hasMoreElements()) { InetAddress adr = nadrs.nextElement(); if (adr != null && !adr.isLoopbackAddress() && (nif.isPointToPoint() || !adr.isLinkLocalAddress())) { return adr; } } } } } } catch (Exception e) { logger.warn("Exception while getting current IP", e); } return null; } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ProcessUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.io.IOException; import java.util.StringTokenizer; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of * {@link org.eclipse.kura.executor.CommandExecutorService} */ @Deprecated public class ProcessUtil { private static final Logger logger = LoggerFactory.getLogger(ProcessUtil.class); private static ExecutorService processExecutor = Executors.newSingleThreadExecutor(); private ProcessUtil() { } public static SafeProcess exec(String command) throws IOException { // Use StringTokenizer since this is the method documented by Runtime StringTokenizer st = new StringTokenizer(command); int count = st.countTokens(); String[] cmdArray = new String[count]; for (int i = 0; i < count; i++) { cmdArray[i] = st.nextToken(); } return exec(cmdArray); } public static SafeProcess exec(final String[] cmdarray) throws IOException { // Serialize process executions. One at a time so we can consume all streams. Future futureSafeProcess = processExecutor.submit(() -> { Thread.currentThread().setName("SafeProcessExecutor"); SafeProcess safeProcess = new SafeProcess(); safeProcess.exec(cmdarray); return safeProcess; }); try { return futureSafeProcess.get(); } catch (Exception e) { logger.error("Error waiting from SafeProcess output"); throw new IOException(e); } } /** * @deprecated The method does nothing */ @Deprecated public static void close(SafeProcess proc) { } public static void destroy(SafeProcess proc) { proc.destroy(); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/QuickSort.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.util; import java.util.Arrays; /** * Utilities to quickly sort an array of values * * @deprecated Use sort methods from {@link Arrays} instead */ @Deprecated public final class QuickSort { private QuickSort() { } /** * @deprecated Use {@link Arrays#sort(int[])} instead */ @Deprecated public static void sort(int[] array) { Arrays.sort(array); } /** * @deprecated Use {@link Arrays#sort(long[])} instead */ @Deprecated public static void sort(long[] array) { Arrays.sort(array); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/SafeProcess.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Arrays; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @deprecated since {@link org.eclipse.kura.core.util} version 1.3 in favor of * {@link org.eclipse.kura.executor.CommandExecutorService} */ @Deprecated public class SafeProcess { private static final Logger logger = LoggerFactory.getLogger(SafeProcess.class); private static ExecutorService streamGobblers = Executors.newFixedThreadPool(2); private Process process; private byte[] inBytes; private byte[] errBytes; private boolean waited; private int exitValue; SafeProcess() { super(); } public OutputStream getOutputStream() { logger.warn("getOutputStream() is unsupported"); return null; } public InputStream getInputStream() { if (!this.waited) { logger.warn("getInputStream() must be called after waitFor()"); } return new ByteArrayInputStream(this.inBytes); } public InputStream getErrorStream() { if (!this.waited) { logger.warn("getErrorStream() must be called after waitFor()"); } return new ByteArrayInputStream(this.errBytes); } void exec(String[] cmdarray) throws IOException { logger.debug("Executing: {}", Arrays.toString(cmdarray)); ProcessBuilder pb = new ProcessBuilder(cmdarray); this.process = pb.start(); // process the input stream Future futureInputGobbler = streamGobblers.submit(() -> { Thread.currentThread().setName("SafeProcess InputStream Gobbler"); return readStreamFully(SafeProcess.this.process.getInputStream()); }); // process the error stream Future futureErrorGobbler = streamGobblers.submit(() -> { Thread.currentThread().setName("SafeProcess ErrorStream Gobbler"); return readStreamFully(SafeProcess.this.process.getErrorStream()); }); // wait for the process execution try { this.inBytes = futureInputGobbler.get(); this.errBytes = futureErrorGobbler.get(); this.exitValue = this.process.waitFor(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new IOException(e); } catch (ExecutionException e) { throw new IOException(e); } finally { closeQuietly(this.process.getInputStream()); closeQuietly(this.process.getErrorStream()); closeQuietly(this.process.getOutputStream()); this.process.destroy(); this.process = null; this.waited = true; } } public int waitFor() throws InterruptedException { return this.exitValue; } public int exitValue() { return this.exitValue; } public void destroy() { if (!this.waited) { logger.warn("Calling destroy() before waitFor() might lead to resource leaks"); Thread.dumpStack(); if (this.process != null) { this.process.destroy(); } } this.inBytes = null; // just in case... this.errBytes = null; this.process = null; } private byte[] readStreamFully(InputStream is) throws IOException { int len; byte[] buf = new byte[1024]; ByteArrayOutputStream inBaos = new ByteArrayOutputStream(1024); while ((len = is.read(buf)) != -1) { inBaos.write(buf, 0, len); } return inBaos.toByteArray(); } private void closeQuietly(InputStream is) { if (is != null) { try { is.close(); is = null; } catch (IOException e) { logger.warn("Failed to close process input stream", e); } } } private void closeQuietly(OutputStream os) { if (os != null) { try { os.close(); os = null; } catch (IOException e) { logger.warn("Failed to close process output stream", e); } } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ThrowableUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import java.io.PrintWriter; import java.io.StringWriter; public class ThrowableUtil { private ThrowableUtil() { } public static String stackTraceAsString(Throwable t) { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); t.printStackTrace(pw); return sw.toString(); } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/util/ValidationUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.util; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; public class ValidationUtil { private ValidationUtil() { } public static void notNull(Object value, String argumentName) throws KuraException { if (value == null) { throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName); } } /** * Throws an KuraException if the string value for the specified argument is empty, null, or whitespace. * * @param obj * @param argumentName * @throws KuraException */ public static void notEmptyOrNull(String value, String argumentName) throws KuraException { if (value == null || value.trim().length() == 0) { throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName); } } /** * Throws an KuraException if the value for the specified argument is null. * * @param obj * @param argumentName * @throws KuraException */ public static void notNegative(int value, String argumentName) throws KuraException { if (value < 0) { throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName); } } /** * Throws an KuraException if the value for the specified argument is null. * * @param obj * @param argumentName * @throws KuraException */ public static void notNegative(short value, String argumentName) throws KuraException { if (value < 0) { throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName); } } /** * Throws an KuraException if the value for the specified argument is null. * * @param obj * @param argumentName * @throws KuraException */ public static void notNegative(long value, String argumentName) throws KuraException { if (value < 0) { throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, argumentName); } } } ================================================ FILE: kura/org.eclipse.kura.core/src/main/java/org/eclipse/kura/core/watchdog/CriticalServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.watchdog; public class CriticalServiceImpl { private final String name; private final long timeout; private long updated; /** * * @param name * @param timeout * timeout for reporting interval in seconds */ public CriticalServiceImpl(String name, long timeout) { this.name = name; this.timeout = timeout; this.updated = System.currentTimeMillis(); } public String getName() { return this.name; } public long getTimeout() { return this.timeout; } public boolean isTimedOut() { long current = System.currentTimeMillis(); return this.timeout < current - this.updated; } public void update() { this.updated = System.currentTimeMillis(); } @Override public String toString() { return "Service Name: " + this.name + ", Timeout(ms): " + this.timeout; } } ================================================ FILE: kura/org.eclipse.kura.core.certificates/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.certificates Bundle-SymbolicName: org.eclipse.kura.core.certificates;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: com.google.gson;version="2.7.0", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.certificate;version="[2.1,2.2)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.crypto;version="[1.1,2.0)", org.eclipse.kura.message;version="[1.0,2.0)", org.eclipse.kura.rest.utils;version="1.0.0", org.eclipse.kura.security.keystore;version="[1.0,2.0)", org.eclipse.osgi.util;version="1.1.0", org.osgi.framework;version="1.10.0", org.osgi.service.component;version="1.2.0", org.osgi.service.useradmin;version="1.1.0", org.osgi.util.tracker;version="1.5.2", org.slf4j;version="1.6.4" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy ================================================ FILE: kura/org.eclipse.kura.core.certificates/OSGI-INF/CertificatesService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.certificates/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.certificates/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.certificates/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about_files/,\ about.html additional.bundles = org.eclipse.osgi,\ org.eclipse.osgi.util,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.certificates/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.certificates 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.certificates.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.core.certificates/src/main/java/org/eclipse/kura/core/certificates/CertificatesManager.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.certificates; import java.security.KeyStore.TrustedCertificateEntry; import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraIOException; import org.eclipse.kura.certificate.CertificatesService; import org.eclipse.kura.certificate.KuraCertificateEntry; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.message.KuraApplicationTopic; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.security.keystore.KeystoreService; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /* * */ public class CertificatesManager implements CertificatesService { private static final Logger logger = LoggerFactory.getLogger(CertificatesManager.class); public static final String APP_ID = "org.eclipse.kura.core.certificates.CertificatesManager"; private static final String RESOURCE_CERTIFICATE_DM = "dm"; private static final String RESOURCE_CERTIFICATE_LOGIN = "login"; private static final String RESOURCE_CERTIFICATE_BUNDLE = "bundle"; private static final String RESOURCE_CERTIFICATE_SSL = "ssl"; private static final String LOGIN_KEYSTORE_SERVICE_PID = "HttpsKeystore"; private static final String SSL_KEYSTORE_SERVICE_PID = "SSLKeystore"; private static final String DEFAULT_KEYSTORE_SERVICE_PID = "org.eclipse.kura.crypto.CryptoService"; private CryptoService cryptoService; private ConfigurationService configurationService; private Map keystoreServices = new HashMap<>(); private BundleContext bundleContext; private ServiceTrackerCustomizer keystoreServiceTrackerCustomizer; private ServiceTracker keystoreServiceTracker; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void unsetCryptoService(CryptoService cryptoService) { if (this.cryptoService == cryptoService) { this.cryptoService = null; } } public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } public void unsetConfigurationService(ConfigurationService configurationService) { if (this.configurationService == configurationService) { this.configurationService = null; } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { this.bundleContext = componentContext.getBundleContext(); this.keystoreServiceTrackerCustomizer = new KeystoreServiceTrackerCustomizer(); initKeystoreServiceTracking(); logger.info("Bundle {} has started!", APP_ID); } protected void deactivate(ComponentContext componentContext) { if (this.keystoreServiceTracker != null) { this.keystoreServiceTracker.close(); } logger.info("Bundle {} is deactivating!", APP_ID); } @Override public Certificate returnCertificate(String alias) throws KuraException { TrustedCertificateEntry cert; try { cert = getCertificateEntry(DEFAULT_KEYSTORE_SERVICE_PID + ":" + alias).getCertificateEntry(); } catch (KuraException e) { return null; } return cert.getTrustedCertificate(); } @Override public void storeCertificate(Certificate cert, String alias) throws KuraException { if (alias.startsWith(RESOURCE_CERTIFICATE_DM)) { storeDmCertificate(cert, alias); } else if (alias.startsWith(RESOURCE_CERTIFICATE_BUNDLE)) { storeTrustRepoCertificate(cert, alias); } else if (alias.startsWith(RESOURCE_CERTIFICATE_LOGIN)) { storeLoginCertificate(cert, alias); } else if (alias.startsWith(RESOURCE_CERTIFICATE_SSL)) { storeSSLCertificate(cert, alias); } } protected void storeLoginCertificate(Certificate cert, String alias) throws KuraException { KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(LOGIN_KEYSTORE_SERVICE_PID, alias, cert); addCertificate(kuraCertificate); } protected void storeSSLCertificate(Certificate cert, String alias) throws KuraException { KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(SSL_KEYSTORE_SERVICE_PID, alias, cert); addCertificate(kuraCertificate); } protected void storeTrustRepoCertificate(Certificate cert, String alias) throws KuraException { KuraCertificateEntry kuraCertificate = new KuraCertificateEntry(DEFAULT_KEYSTORE_SERVICE_PID, alias, cert); addCertificate(kuraCertificate); } protected void storeDmCertificate(Certificate cert, String alias) throws KuraException { storeTrustRepoCertificate(cert, alias); } @Override public Enumeration listBundleCertificatesAliases() { return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID); } @Override public Enumeration listDMCertificatesAliases() { return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID); } @Override public Enumeration listSSLCertificatesAliases() { return listCertificatesAliases(SSL_KEYSTORE_SERVICE_PID); } @Override public Enumeration listCACertificatesAliases() { return listCertificatesAliases(DEFAULT_KEYSTORE_SERVICE_PID); } @Override public void removeCertificate(String alias) throws KuraException { for (Entry keystoreServiceEntry : this.keystoreServices.entrySet()) { keystoreServiceEntry.getValue().deleteEntry(alias); } } @Override public boolean verifySignature(KuraApplicationTopic kuraTopic, KuraPayload kuraPayload) { return true; } protected Enumeration listCertificatesAliases(String keystoreId) { try { return Collections.enumeration(getKeystore(keystoreId).getAliases()); } catch (IllegalArgumentException | KuraException e) { return Collections.emptyEnumeration(); } } @Override public List getCertificates() throws KuraException { List certificates = new ArrayList<>(); for (Entry keystoreServiceEntry : this.keystoreServices.entrySet()) { String keystoreId = keystoreServiceEntry.getKey(); Map keystoreEntries = keystoreServiceEntry.getValue().getEntries(); keystoreEntries.entrySet().stream().filter(entry -> entry.getValue() instanceof TrustedCertificateEntry) .forEach(entry -> { String alias = entry.getKey(); certificates.add(new KuraCertificateEntry(keystoreId, alias, (TrustedCertificateEntry) entry.getValue())); }); } return certificates; } @Override public KuraCertificateEntry getCertificateEntry(String id) throws KuraException { String keystoreId = KuraCertificateEntry.getKeystoreId(id); String alias = KuraCertificateEntry.getAlias(id); java.security.KeyStore.Entry keystoreEntry = getKeystore(keystoreId).getEntry(alias); if (keystoreEntry instanceof TrustedCertificateEntry) { return new KuraCertificateEntry(keystoreId, alias, (TrustedCertificateEntry) keystoreEntry); } else { throw new KuraIOException("Failed to retrieve certificate " + id); } } @Override public void updateCertificate(KuraCertificateEntry certificate) throws KuraException { addCertificate(certificate); } @Override public void addCertificate(KuraCertificateEntry certificate) throws KuraException { getKeystore(certificate.getKeystoreId()).setEntry(certificate.getAlias(), certificate.getCertificateEntry()); } @Override public void deleteCertificate(String id) throws KuraException { String keystoreId = KuraCertificateEntry.getKeystoreId(id); String alias = KuraCertificateEntry.getAlias(id); getKeystore(keystoreId).deleteEntry(alias); } private void initKeystoreServiceTracking() { String filterString = String.format("(&(%s=%s))", Constants.OBJECTCLASS, KeystoreService.class.getName()); Filter filter = null; try { filter = this.bundleContext.createFilter(filterString); } catch (InvalidSyntaxException e) { logger.error("Filter setup exception ", e); } this.keystoreServiceTracker = new ServiceTracker<>(this.bundleContext, filter, this.keystoreServiceTrackerCustomizer); this.keystoreServiceTracker.open(); } private KeystoreService getKeystore(String keystoreId) throws KuraException { KeystoreService service = this.keystoreServices.get(keystoreId); if (service == null) { throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "KeystoreService " + keystoreId + " not found"); } return service; } private final class KeystoreServiceTrackerCustomizer implements ServiceTrackerCustomizer { private static final String KURA_SERVICE_PID = "kura.service.pid"; @Override public KeystoreService addingService(final ServiceReference reference) { String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID); CertificatesManager.this.keystoreServices.put(kuraServicePid, CertificatesManager.this.bundleContext.getService(reference)); return CertificatesManager.this.keystoreServices.get(kuraServicePid); } @Override public void modifiedService(final ServiceReference reference, final KeystoreService service) { String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID); CertificatesManager.this.keystoreServices.put(kuraServicePid, CertificatesManager.this.bundleContext.getService(reference)); } @Override public void removedService(final ServiceReference reference, final KeystoreService service) { String kuraServicePid = (String) reference.getProperty(KURA_SERVICE_PID); CertificatesManager.this.keystoreServices.remove(kuraServicePid); } } } ================================================ FILE: kura/org.eclipse.kura.core.certificates/src/main/java/org/eclipse/kura/core/certificates/KeyStoreManagement.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.certificates; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; final class KeyStoreManagement { private static final String ENV_JAVA_KEYSTORE = System.getenv("JAVA_HOME") + "/jre/lib/security/cacerts"; private KeyStoreManagement() { } static KeyStore loadKeyStore(byte[] password) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { return loadKeyStore(new String(password).toCharArray()); } static void saveKeyStore(KeyStore keystore, byte[] password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { saveKeyStore(keystore, new String(password).toCharArray()); } static KeyStore loadKeyStore(char[] password) throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException { return loadKeyStore(ENV_JAVA_KEYSTORE, new String(password).toCharArray()); } static void saveKeyStore(KeyStore keystore, char[] password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { saveKeyStore(keystore, ENV_JAVA_KEYSTORE, new String(password).toCharArray()); } static void saveKeyStore(String keystorePath, KeyStore keystore, char[] password) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { saveKeyStore(keystore, keystorePath, new String(password).toCharArray()); } static KeyStore loadKeyStore(String location, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException, KeyStoreException { FileInputStream is = null; try { is = new FileInputStream(location); KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(is, password); is.close(); return keystore; } finally { if (is != null) { is.close(); } } } static void saveKeyStore(KeyStore keystore, String location, char[] password) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { FileOutputStream fos = null; try { fos = new FileOutputStream(location); keystore.store(fos, password); fos.flush(); fos.close(); } finally { if (fos != null) { fos.close(); } } } } ================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.cloud.factory Bundle-SymbolicName: org.eclipse.kura.core.cloud.factory;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="1.6.0", org.eclipse.kura.cloud;version="[1.0,2.0)", org.eclipse.kura.cloud.factory;version="[1.1,1.2)", org.eclipse.kura.cloudconnection;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.factory;version="[1.0,1.1)", org.eclipse.kura.configuration;version="[1.0,2.0)", org.eclipse.kura.data;version="[1.0,2.0)", org.osgi.framework;version="1.10.0", org.osgi.service.component ================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/OSGI-INF/cloudServiceFactory.xml ================================================ createConfiguration ================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files src.includes = about.html,\ about_files/ source.. = src/main/java/ ================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.cloud.factory 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml org.apache.maven.plugins maven-checkstyle-plugin true ================================================ FILE: kura/org.eclipse.kura.core.cloud.factory/src/main/java/org/eclipse/kura/core/cloud/factory/DefaultCloudServiceFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.cloud.factory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloud.CloudService; import org.eclipse.kura.cloud.factory.CloudServiceFactory; import org.eclipse.kura.cloudconnection.CloudConnectionManager; import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.data.DataTransportService; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.service.component.ComponentConstants; import org.osgi.service.component.ComponentContext; /** * The Kura default {@link CloudServiceFactory} implements a three layer stack architecture. * Each layer is an OSGi Declarative Services Factory Component and provides a service as follows: * * * * * * * * * * * * * * * * * * * * * * *
Factory PIDService interface
org.eclipse.kura.cloud.CloudService{@link CloudService}
org.eclipse.kura.data.DataService{@link CloudService}
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport{@link DataTransportService}
*
* When a new CloudService is created the factory creates also a DataService and a DataTransportService. * Since the pid parameter of {@link #createConfiguration(String)} only specifies the PID of * the CloudService layer, a convention is needed to derive the PIDs of the lower layers. *
*
* The default stack instance is special. * For backward compatibility the PIDs of the default stack must be as follows: * * * * * * * * * * * * * * * * * * * * * * *
PID (kura.service.pid)Factory PID
org.eclipse.kura.cloud.CloudServiceorg.eclipse.kura.cloud.CloudService
org.eclipse.kura.data.DataServiceorg.eclipse.kura.data.DataService
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
*
* * For other stack instances the convention used to generate the PIDs for the lower layers is * to use the sub string in the CloudService PID starting after the first occurrence of the '-' character and append * the sub string to the PIDs of the default stack above, for example: * * * * * * * * * * * * * * * * * * * * * * *
PID (kura.service.pid)Factory PID
org.eclipse.kura.cloud.CloudService-2org.eclipse.kura.cloud.CloudService
org.eclipse.kura.data.DataService-2org.eclipse.kura.data.DataService
org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport
*
* The (configuration of) layer instances of each stack are persisted to Kura snapshot and * recreated at every Kura start. * On startup every stack must be properly reassembled with the right layer instances. *
* This can be achieved using a standard OSGi Declarative Services magic property set in a layer configuration * specifying the layer dependency on a specific PID of its next lower layer. * The following example shows this selective dependency mechanism for the DataService and MqttDataTransport services. *
* The DataService component definition specifies a dependency on a DataTransportService as follows: * *
 * <reference name="DataTransportService"
 *              bind="setDataTransportService"
 *              unbind="unsetDataTransportService"
 *              cardinality="1..1"
 *              policy="static"
 *              interface="org.eclipse.kura.data.DataTransportService"/>
 * 
* *
* The DataService with PID org.eclipse.kura.data.DataService-2 needs to be activated * only when its dependency on a specific DataTransportService with * PID org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-2 is satisfied. *
* The OSGi Declarative Services specification provides a magic <reference name>.target * property that can be set at runtime to specify a selective dependency. *
* In the above example the org.eclipse.kura.data.DataService-2 component instance will have a * DataTransportService.target property set to the value: * *
 * (kura.service.pid = org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport - 2)
 * 
* * Since {@link org.eclipse.kura.cloud.factory} 1.1.0, the CloudService instance contains a property that maps the * instance with the {@link org.eclipse.kura.cloud.factory.CloudServiceFactory} implementation that generated it. * *
*/ public class DefaultCloudServiceFactory implements CloudServiceFactory, CloudConnectionFactory { private static final String FACTORY_PID = "org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory"; // The following constants must match the factory component definitions private static final String CLOUD_SERVICE_FACTORY_PID = "org.eclipse.kura.cloud.CloudService"; private static final String DATA_SERVICE_FACTORY_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String CLOUD_SERVICE_PID = "org.eclipse.kura.cloud.CloudService"; private static final String DATA_SERVICE_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String DATA_SERVICE_REFERENCE_NAME = "DataService"; private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = "DataTransportService"; private static final String REFERENCE_TARGET_VALUE_FORMAT = "(" + ConfigurationService.KURA_SERVICE_PID + "=%s)"; private static final Pattern MANAGED_CLOUD_SERVICE_PID_PATTERN = Pattern .compile("^org\\.eclipse\\.kura\\.cloud\\.CloudService(-[a-zA-Z0-9]+)?$"); private ConfigurationService configurationService; private BundleContext bundleContext; protected void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } protected void unsetConfigurationService(ConfigurationService configurationService) { if (configurationService == this.configurationService) { this.configurationService = null; } } public void activate(final ComponentContext context) { this.bundleContext = context.getBundleContext(); } @Override public String getFactoryPid() { return CLOUD_SERVICE_FACTORY_PID; } @Override public void createConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } // create the CloudService layer and set the selective dependency on the DataService PID Map cloudServiceProperties = new HashMap<>(); String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; cloudServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataServicePid)); cloudServiceProperties.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID); cloudServiceProperties.put(KURA_CLOUD_CONNECTION_FACTORY_PID, FACTORY_PID); this.configurationService.createFactoryConfiguration(CLOUD_SERVICE_FACTORY_PID, pid, cloudServiceProperties, false); // create the DataService layer and set the selective dependency on the DataTransportService PID Map dataServiceProperties = new HashMap(); name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; dataServiceProperties.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, dataTransportServicePid)); this.configurationService.createFactoryConfiguration(DATA_SERVICE_FACTORY_PID, dataServicePid, dataServiceProperties, false); // create the DataTransportService layer and take a snapshot this.configurationService.createFactoryConfiguration(DATA_TRANSPORT_SERVICE_FACTORY_PID, dataTransportServicePid, null, true); } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public void deleteConfiguration(String pid) throws KuraException { String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } this.configurationService.deleteFactoryConfiguration(pid, false); this.configurationService.deleteFactoryConfiguration(dataServicePid, false); this.configurationService.deleteFactoryConfiguration(dataTransportServicePid, true); } } @Override public List getStackComponentsPids(String pid) throws KuraException { List componentPids = new ArrayList(); String[] parts = pid.split("-"); if (parts.length != 0 && CLOUD_SERVICE_PID.equals(parts[0])) { String suffix = null; if (parts.length > 1) { suffix = parts[1]; } String dataServicePid = DATA_SERVICE_PID; String dataTransportServicePid = DATA_TRANSPORT_SERVICE_PID; if (suffix != null) { dataServicePid += "-" + suffix; dataTransportServicePid += "-" + suffix; } componentPids.add(pid); componentPids.add(dataServicePid); componentPids.add(dataTransportServicePid); return componentPids; } else { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Invalid PID '{}'", pid); } } @Override public Set getManagedCloudConnectionPids() throws KuraException { try { return this.bundleContext.getServiceReferences(CloudConnectionManager.class, null).stream().filter(ref -> { final Object kuraServicePid = ref.getProperty(ConfigurationService.KURA_SERVICE_PID); if (!(kuraServicePid instanceof String)) { return false; } return MANAGED_CLOUD_SERVICE_PID_PATTERN.matcher((String) kuraServicePid).matches() && (FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_SERVICE_FACTORY_PID)) || FACTORY_PID.equals(ref.getProperty(KURA_CLOUD_CONNECTION_FACTORY_PID))); }).map(ref -> (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID)).collect(Collectors.toSet()); } catch (InvalidSyntaxException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, e); } } @Override public Set getManagedCloudServicePids() throws KuraException { return getManagedCloudConnectionPids(); } } ================================================ FILE: kura/org.eclipse.kura.core.comm/.gitignore ================================================ /target /bin ================================================ FILE: kura/org.eclipse.kura.core.comm/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.comm Bundle-SymbolicName: org.eclipse.kura.core.comm;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: javax.comm;version="1.2.0", javax.microedition.io, org.apache.logging.log4j;version="2.8.2", org.apache.logging.log4j.util;version="2.8.2", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.comm;version="[1.1,1.2)", org.osgi.service.component;version="1.2.0", org.osgi.service.io;version="1.0.0" ================================================ FILE: kura/org.eclipse.kura.core.comm/OSGI-INF/comm.xml ================================================ comm ================================================ FILE: kura/org.eclipse.kura.core.comm/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.comm/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.comm/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/ source.. = src/main/java/ additional.bundles = org.eclipse.kura.api,\ slf4j.api,\ org.eclipse.osgi,\ org.eclipse.equinox.io src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.comm/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.comm 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.comm.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.core.comm/src/main/java/org/eclipse/kura/core/comm/CommConnectionFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.comm; import static org.eclipse.kura.comm.CommURI.parseString; import java.io.IOException; import javax.microedition.io.Connection; import org.osgi.service.io.ConnectionFactory; public class CommConnectionFactory implements ConnectionFactory { @Override public Connection createConnection(String name, int mode, boolean timeouts) throws IOException { try { return new CommConnectionImpl(parseString(name), mode, timeouts); } catch (IOException e) { throw e; // re-throw } catch (Throwable t) { throw new IOException(t); } } } ================================================ FILE: kura/org.eclipse.kura.core.comm/src/main/java/org/eclipse/kura/core/comm/CommConnectionImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.comm; import static java.util.Objects.requireNonNull; import java.io.Closeable; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.Buffer; import java.nio.ByteBuffer; import java.util.StringJoiner; import javax.comm.CommPort; import javax.comm.CommPortIdentifier; import javax.comm.NoSuchPortException; import javax.comm.PortInUseException; import javax.comm.SerialPort; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.eclipse.kura.KuraException; import org.eclipse.kura.comm.CommConnection; import org.eclipse.kura.comm.CommURI; public class CommConnectionImpl implements CommConnection, Closeable { private static final String SEND_MESSAGE = "sendMessage() - {}"; private static final String JAVA_EXT_DIRS = "java.ext.dirs"; private static final String KURA_EXT_DIR = "kura.ext.dir"; private static final Logger logger = LogManager.getLogger(CommConnectionImpl.class); // set up the appropriate ext dir for RXTX extra device nodes static { String kuraExtDir = System.getProperty(KURA_EXT_DIR); if (kuraExtDir != null) { StringBuffer sb = new StringBuffer(); String existingDirs = System.getProperty(JAVA_EXT_DIRS); if (existingDirs != null) { if (!existingDirs.contains(kuraExtDir)) { sb.append(existingDirs).append(File.pathSeparator).append(kuraExtDir); System.setProperty(JAVA_EXT_DIRS, sb.toString()); } } else { sb.append(kuraExtDir); System.setProperty(JAVA_EXT_DIRS, sb.toString()); } } } private final CommURI commUri; private SerialPort serialPort; private InputStream inputStream; private OutputStream outputStream; public CommConnectionImpl(CommURI commUri, int mode, boolean timeouts) throws IOException, NoSuchPortException, PortInUseException { requireNonNull(commUri); this.commUri = commUri; final String port = this.commUri.getPort(); final int baudRate = this.commUri.getBaudRate(); final int dataBits = this.commUri.getDataBits(); final int stopBits = this.commUri.getStopBits(); final int parity = this.commUri.getParity(); final int flowControl = this.commUri.getFlowControl(); final int openTimeout = this.commUri.getOpenTimeout(); final int receiveTimeout = this.commUri.getReceiveTimeout(); final CommPortIdentifier commPortIdentifier = CommPortIdentifier.getPortIdentifier(port); final CommPort commPort = commPortIdentifier.open(this.getClass().getName(), openTimeout); if (commPort == null) { throw new NoSuchPortException("CommPortIdentifier.open() returned a null port"); } try { if (commPort instanceof SerialPort) { this.serialPort = (SerialPort) commPort; this.serialPort.setSerialPortParams(baudRate, dataBits, stopBits, parity); this.serialPort.setFlowControlMode(flowControl); if (receiveTimeout > 0) { this.serialPort.enableReceiveTimeout(receiveTimeout); if (!this.serialPort.isReceiveTimeoutEnabled()) { throw new IOException("Serial receive timeout not supported by driver"); } } } else { throw new IOException("Unsupported Port Type"); } } catch (final Exception e) { logger.error("Failed to configure COM port", e); commPort.close(); throw new IOException(e); } } @Override public CommURI getURI() { return this.commUri; } @Override public DataInputStream openDataInputStream() throws IOException { return new DataInputStream(openInputStream()); } @Override public synchronized InputStream openInputStream() throws IOException { checkIfClosed(); if (this.inputStream == null) { this.inputStream = this.serialPort.getInputStream(); } return this.inputStream; } @Override public DataOutputStream openDataOutputStream() throws IOException { return new DataOutputStream(openOutputStream()); } @Override public synchronized OutputStream openOutputStream() throws IOException { checkIfClosed(); if (this.outputStream == null) { this.outputStream = this.serialPort.getOutputStream(); } return this.outputStream; } @Override public synchronized void close() throws IOException { if (this.serialPort != null) { this.serialPort.notifyOnDataAvailable(false); this.serialPort.removeEventListener(); if (this.inputStream != null) { this.inputStream.close(); this.inputStream = null; } if (this.outputStream != null) { this.outputStream.close(); this.outputStream = null; } this.serialPort.close(); this.serialPort = null; } } private void checkIfClosed() throws IOException { if (this.serialPort == null) { throw new IOException("Connection is already closed"); } } @Override public synchronized void sendMessage(byte[] message) throws KuraException, IOException { checkIfClosed(); if (message == null) { throw new NullPointerException("Message must not be null"); } logger.debug(SEND_MESSAGE, () -> getBytesAsString(message)); if (this.outputStream == null) { openOutputStream(); } this.outputStream.write(message, 0, message.length); this.outputStream.flush(); } @Override public synchronized byte[] sendCommand(byte[] command, int timeout) throws KuraException, IOException { checkIfClosed(); if (command == null) { throw new NullPointerException("Serial command must not be null"); } logger.debug(SEND_MESSAGE, () -> getBytesAsString(command)); if (this.outputStream == null) { openOutputStream(); } if (this.inputStream == null) { openInputStream(); } byte[] dataInBuffer = flushSerialBuffer(); if (dataInBuffer != null && dataInBuffer.length > 0) { logger.warn("eating bytes in the serial buffer input stream before sending command: {}", getBytesAsString(dataInBuffer)); } this.outputStream.write(command, 0, command.length); this.outputStream.flush(); ByteBuffer buffer = getResponse(timeout); if (buffer != null) { byte[] response = new byte[buffer.limit()]; buffer.get(response, 0, response.length); return response; } else { return null; } } @Override public synchronized byte[] sendCommand(byte[] command, int timeout, int demark) throws KuraException, IOException { checkIfClosed(); if (command == null) { throw new NullPointerException("Serial command must not be null"); } logger.debug(SEND_MESSAGE, getBytesAsString(command)); if (this.outputStream == null) { openOutputStream(); } if (this.inputStream == null) { openInputStream(); } byte[] dataInBuffer = flushSerialBuffer(); if (dataInBuffer != null && dataInBuffer.length > 0) { logger.warn("eating bytes in the serial buffer input stream before sending command: {}", getBytesAsString(dataInBuffer)); } this.outputStream.write(command, 0, command.length); this.outputStream.flush(); ByteBuffer buffer = getResponse(timeout, demark); if (buffer != null) { byte[] response = new byte[buffer.limit()]; buffer.get(response, 0, response.length); return response; } else { return null; } } @Override public synchronized byte[] flushSerialBuffer() throws KuraException, IOException { checkIfClosed(); ByteBuffer buffer = getResponse(50); if (buffer != null) { byte[] response = new byte[buffer.limit()]; buffer.get(response, 0, response.length); return response; } else { return null; } } private synchronized ByteBuffer getResponse(int timeout) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(4096); long start = System.currentTimeMillis(); while (this.inputStream.available() < 1 && System.currentTimeMillis() - start < timeout) { try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } while (this.inputStream.available() >= 1) { int c = this.inputStream.read(); buffer.put((byte) c); } // The buffer is casted to Buffer for Java8 compatibility ((Buffer) buffer).flip(); return buffer.limit() > 0 ? buffer : null; } private synchronized ByteBuffer getResponse(int timeout, int demark) throws IOException { ByteBuffer buffer = ByteBuffer.allocate(4096); long start = System.currentTimeMillis(); while (this.inputStream.available() < 1 && System.currentTimeMillis() - start < timeout) { try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } start = System.currentTimeMillis(); do { if (this.inputStream.available() > 0) { start = System.currentTimeMillis(); int c = this.inputStream.read(); buffer.put((byte) c); } } while (System.currentTimeMillis() - start < demark); // The buffer is casted to Buffer for Java8 compatibility ((Buffer) buffer).flip(); return buffer.limit() > 0 ? buffer : null; } /* default */ static String getBytesAsString(byte[] bytes) { if (bytes == null) { return null; } StringJoiner sj = new StringJoiner(" "); for (byte b : bytes) { sj.add(String.format("%02X", b)); } return sj.toString(); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/.gitignore ================================================ /target /bin ================================================ FILE: kura/org.eclipse.kura.core.configuration/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.configuration Bundle-SymbolicName: org.eclipse.kura.core.configuration;singleton:=true Bundle-Version: 3.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: javax.crypto, javax.xml.namespace, javax.xml.parsers, javax.xml.stream, javax.xml.transform, javax.xml.transform.dom, javax.xml.transform.stream, org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.audit;version="[1.0,2.0)", org.eclipse.kura.cloud;version="[1.1,1.2)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.request;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.2,1.3)", org.eclipse.kura.configuration.metatype;version="[1.1,2.0)", org.eclipse.kura.core.util;version="[2.0,3.0)", org.eclipse.kura.crypto;version="[1.4,2.0)", org.eclipse.kura.marshalling;version="[1.1,2.0)", org.eclipse.kura.message;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.0,2.0)", org.eclipse.kura.util.service;version="[1.0,2.0)", org.eclipse.kura.wire;version="[2.0,3.0)", org.eclipse.kura.wire.graph;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.cm;version="1.4.0", org.osgi.service.component;version="1.2.0", org.osgi.service.component.runtime;version="1.3.0", org.osgi.service.component.runtime.dto;version="1.3.0", org.osgi.service.event;version="1.3.0", org.osgi.service.metatype;version="1.2.0", org.osgi.util.tracker;version="[1.5.0,2.0.0)", org.slf4j;version="1.6.4", org.w3c.dom, org.xml.sax Export-Package: org.eclipse.kura.core.configuration;version="2.0.0", org.eclipse.kura.core.configuration.metatype;version="1.0.0", org.eclipse.kura.core.configuration.util;version="2.0.0" ================================================ FILE: kura/org.eclipse.kura.core.configuration/OSGI-INF/cloudConfigurationHandler.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.configuration/OSGI-INF/configuration.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.configuration/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.configuration/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.configuration/build.properties ================================================ bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/,\ OSGI-INF/cloudConfigurationHandler.xml src.includes = about.html,\ about_files/ source.. = src/main/java/ additional.bundles = org.eclipse.kura.api,\ slf4j.api,\ org.eclipse.osgi ================================================ FILE: kura/org.eclipse.kura.core.configuration/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.configuration 3.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.configuration.test/target/site/jacoco-aggregate/jacoco.xml org.apache.maven.plugins maven-checkstyle-plugin true ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/CloudConfigurationHandler.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.audit.AuditContext; import org.eclipse.kura.audit.AuditContext.Scope; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerContext; import org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.eclipse.kura.system.SystemService; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @deprecated Please switch to CONF-V2 and corresponding REST APIs * (https://eclipse-kura.github.io/kura/docs-release-5.6/references/rest-apis/rest-configuration-service-v2/) */ @Deprecated public class CloudConfigurationHandler implements RequestHandler { private static final String EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE = "Expected one resource but found none"; private static final String EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE = "Expected at most two resource(s) but found {}"; private static final String CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE = "Cannot find resource with name: {}"; private static final String BAD_REQUEST_TOPIC_MESSAGE = "Bad request topic: {}"; private static Logger logger = LoggerFactory.getLogger(CloudConfigurationHandler.class); public static final String APP_ID = "CONF-V1"; /* GET or PUT */ public static final String RESOURCE_CONFIGURATIONS = "configurations"; /* GET */ public static final String RESOURCE_SNAPSHOTS = "snapshots"; /* EXEC */ public static final String RESOURCE_SNAPSHOT = "snapshot"; public static final String RESOURCE_ROLLBACK = "rollback"; private SystemService systemService; private ConfigurationService configurationService; private BundleContext bundleContext; private ScheduledExecutorService executor; protected void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } protected void unsetConfigurationService(ConfigurationService configurationService) { this.configurationService = null; } protected void setSystemService(SystemService systemService) { this.systemService = systemService; } protected void unsetSystemService(SystemService systemService) { this.systemService = null; } public void setRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) { try { requestHandlerRegistry.registerRequestHandler(APP_ID, this); } catch (KuraException e) { logger.info("Unable to register cloudlet {} in {}", APP_ID, requestHandlerRegistry.getClass().getName()); } } public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) { try { requestHandlerRegistry.unregister(APP_ID); } catch (KuraException e) { logger.info("Unable to register cloudlet {} in {}", APP_ID, requestHandlerRegistry.getClass().getName()); } } protected void activate(ComponentContext componentContext) { this.bundleContext = componentContext.getBundleContext(); this.executor = Executors.newSingleThreadScheduledExecutor(); } protected void deactivate(ComponentContext componentContext) { this.executor.shutdownNow(); } @Override public KuraMessage doGet(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { List resources = getRequestResources(reqMessage); if (resources.isEmpty()) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE); throw new KuraException(KuraErrorCode.BAD_REQUEST); } KuraPayload payload; if (resources.get(0).equals(RESOURCE_CONFIGURATIONS)) { payload = doGetConfigurations(resources); } else if (resources.get(0).equals(RESOURCE_SNAPSHOTS)) { payload = doGetSnapshots(resources); } else { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0)); throw new KuraException(KuraErrorCode.NOT_FOUND); } return new KuraMessage(payload); } @Override public KuraMessage doPut(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { List resources = getRequestResources(reqMessage); if (resources.isEmpty()) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE); throw new KuraException(KuraErrorCode.BAD_REQUEST); } KuraPayload payload; if (resources.get(0).equals(RESOURCE_CONFIGURATIONS)) { payload = doPutConfigurations(resources, reqMessage.getPayload()); } else { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0)); throw new KuraException(KuraErrorCode.NOT_FOUND); } return new KuraMessage(payload); } @Override public KuraMessage doExec(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { List resources = getRequestResources(reqMessage); if (resources.isEmpty()) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_ONE_RESOURCE_BUT_FOUND_NONE_MESSAGE); throw new KuraException(KuraErrorCode.BAD_REQUEST); } KuraPayload payload; if (resources.get(0).equals(RESOURCE_SNAPSHOT)) { payload = doExecSnapshot(resources); } else if (resources.get(0).equals(RESOURCE_ROLLBACK)) { payload = doExecRollback(resources); } else { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(CANNOT_FIND_RESOURCE_WITH_NAME_MESSAGE, resources.get(0)); throw new KuraException(KuraErrorCode.NOT_FOUND); } return new KuraMessage(payload); } private KuraPayload doGetSnapshots(List resources) throws KuraException { KuraResponsePayload responsePayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); if (resources.size() > 2) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error("Expected one or two resource(s) but found {}", resources.size()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } String snapshotId = resources.size() == 2 ? resources.get(1) : null; if (snapshotId != null) { long sid = Long.parseLong(snapshotId); XmlComponentConfigurations xmlConfigs = ((ConfigurationServiceImpl) this.configurationService) .loadEncryptedSnapshotFileContent(sid); // // marshall the response List configs = xmlConfigs.getConfigurations(); configs.forEach(config -> ((ConfigurationServiceImpl) this.configurationService) .decryptConfigurationProperties(config.getConfigurationProperties())); byte[] body = toResponseBody(xmlConfigs); // // Build payload responsePayload.setBody(body); } else { // get the list of snapshot IDs and put them into a response object Set sids = null; try { sids = this.configurationService.getSnapshots(); } catch (KuraException e) { logger.error("Error listing snapshots: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LISTING, e); } List snapshotIds = new ArrayList<>(sids); XmlSnapshotIdResult xmlResult = new XmlSnapshotIdResult(); xmlResult.setSnapshotIds(snapshotIds); // // marshall the response byte[] body = toResponseBody(xmlResult); // // Build payload responsePayload.setBody(body); } return responsePayload; } @SuppressWarnings("unchecked") private List getRequestResources(KuraMessage reqMessage) throws KuraException { Object requestObject = reqMessage.getProperties().get(ARGS_KEY.value()); List resources; if (requestObject instanceof List) { resources = (List) requestObject; } else { throw new KuraException(KuraErrorCode.BAD_REQUEST); } return resources; } private KuraPayload doGetConfigurations(List resources) throws KuraException { if (resources.size() > 2) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } String pid = resources.size() == 2 ? resources.get(1) : null; // // get current configuration with descriptors List configs = new ArrayList<>(); try { if (pid == null) { configs = getAllConfigurations(); } else { configs = getConfiguration(pid); } } catch (KuraException e) { logger.error("Error getting component configurations: {}", e); throw new KuraException(KuraErrorCode.BAD_REQUEST); } XmlComponentConfigurations xmlConfigs = new XmlComponentConfigurations(); xmlConfigs.setConfigurations(configs); // // marshall byte[] body = toResponseBody(xmlConfigs); // // Build response payload KuraResponsePayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); response.setBody(body); return response; } private List getConfiguration(String pid) throws KuraException { List configs = new ArrayList<>(); ComponentConfiguration cc = this.configurationService.getComponentConfiguration(pid); if (cc != null) { configs.add(cc); } return configs; } private List getAllConfigurations() { List configs = new ArrayList<>(); List pidsToIgnore = this.systemService.getDeviceManagementServiceIgnore(); // the configuration for all components has been requested Set componentPids = this.configurationService.getConfigurableComponentPids(); if (pidsToIgnore != null) { Set filteredComponentPids = componentPids.stream() .filter(((Predicate) pidsToIgnore::contains).negate()).collect(Collectors.toSet()); filteredComponentPids.forEach(componentPid -> { ComponentConfiguration cc; try { cc = this.configurationService.getComponentConfiguration(componentPid); // TODO: define a validate method for ComponentConfiguration if (cc == null) { logger.error("null ComponentConfiguration"); return; } if (cc.getPid() == null || cc.getPid().isEmpty()) { logger.error("null or empty ComponentConfiguration PID"); return; } if (cc.getDefinition() == null) { logger.error("null OCD for ComponentConfiguration PID {}", cc.getPid()); return; } if (cc.getDefinition().getId() == null || cc.getDefinition().getId().isEmpty()) { logger.error("null or empty OCD ID for ComponentConfiguration PID {}. OCD ID: {}", cc.getPid(), cc.getDefinition().getId()); return; } configs.add(cc); } catch (KuraException e) { // Nothing needed here } }); } return configs; } private KuraPayload doPutConfigurations(List resources, KuraPayload reqPayload) throws KuraException { if (resources.size() > 2) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } String pid = resources.size() == 2 ? resources.get(1) : null; XmlComponentConfigurations xmlConfigs = null; try { // unmarshall the response if (reqPayload.getBody() == null || reqPayload.getBody().length == 0) { throw new IllegalArgumentException("body"); } String s = new String(reqPayload.getBody(), "UTF-8"); logger.info("Received new Configuration"); xmlConfigs = unmarshal(s, XmlComponentConfigurations.class); } catch (Exception e) { logger.error("Error unmarshalling the request body: {}", e); throw new KuraException(KuraErrorCode.BAD_REQUEST); } this.executor.schedule(new UpdateConfigurationsCallable(pid, xmlConfigs, this.configurationService), 1000, TimeUnit.MILLISECONDS); return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); } private KuraPayload doExecRollback(List resources) throws KuraException { if (resources.size() > 2) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(EXPECTED_AT_MOST_TWO_RESOURCES_BUT_FOUND_MESSAGE, resources.size()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } String snapshotId = resources.size() == 2 ? resources.get(1) : null; Long sid; try { sid = snapshotId != null ? Long.parseLong(snapshotId) : null; } catch (NumberFormatException e) { logger.error("Bad numeric numeric format for snapshot ID: {}", snapshotId); throw new KuraException(KuraErrorCode.BAD_REQUEST); } this.executor.schedule(new RollbackCallable(sid, this.configurationService), 1000, TimeUnit.MILLISECONDS); return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); } private KuraPayload doExecSnapshot(List resources) throws KuraException { if (resources.size() > 1) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error("Expected one resource(s) but found {}", resources.size()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } // take a new snapshot and get the id long snapshotId; try { snapshotId = this.configurationService.snapshot(); } catch (KuraException e) { logger.error("Error taking snapshot: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_TAKING, e); } List snapshotIds = new ArrayList<>(); snapshotIds.add(snapshotId); XmlSnapshotIdResult xmlResult = new XmlSnapshotIdResult(); xmlResult.setSnapshotIds(snapshotIds); byte[] body = toResponseBody(xmlResult); KuraResponsePayload responsePayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); responsePayload.setBody(body); return responsePayload; } private byte[] toResponseBody(Object o) throws KuraException { // // marshall the response String result = null; try { result = marshal(o); } catch (Exception e) { logger.error("Error marshalling snapshots: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LOADING, e); } byte[] body = null; try { body = result.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { logger.error("Error encoding response body: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_LOADING, e); } return body; } private ServiceReference[] getXmlMarshallers() { String filterString = String.format("(&(kura.service.pid=%s))", "org.eclipse.kura.xml.marshaller.unmarshaller.provider"); return ServiceUtil.getServiceReferences(this.bundleContext, Marshaller.class, filterString); } private ServiceReference[] getXmlUnmarshallers() { String filterString = String.format("(&(kura.service.pid=%s))", "org.eclipse.kura.xml.marshaller.unmarshaller.provider"); return ServiceUtil.getServiceReferences(this.bundleContext, Unmarshaller.class, filterString); } private void ungetServiceReferences(final ServiceReference[] refs) { ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } protected T unmarshal(String xmlString, Class clazz) throws KuraException { T result = null; ServiceReference[] unmarshallerSRs = getXmlUnmarshallers(); try { for (final ServiceReference unmarshallerSR : unmarshallerSRs) { Unmarshaller unmarshaller = this.bundleContext.getService(unmarshallerSR); result = unmarshaller.unmarshal(xmlString, clazz); if (result != null) { break; } } } catch (Exception e) { logger.warn("Failed to extract persisted configuration."); } finally { ungetServiceReferences(unmarshallerSRs); } if (result == null) { throw new KuraException(KuraErrorCode.DECODER_ERROR, "value"); } return result; } protected String marshal(Object object) { String result = null; ServiceReference[] marshallerSRs = getXmlMarshallers(); try { for (final ServiceReference marshallerSR : marshallerSRs) { Marshaller marshaller = this.bundleContext.getService(marshallerSR); result = marshaller.marshal(object); if (result != null) { break; } } } catch (Exception e) { logger.warn("Failed to marshal configuration."); } finally { ungetServiceReferences(marshallerSRs); } return result; } } class UpdateConfigurationsCallable implements Callable { private static Logger logger = LoggerFactory.getLogger(UpdateConfigurationsCallable.class); private final String pid; private final XmlComponentConfigurations xmlConfigurations; private final ConfigurationService configurationService; private final AuditContext auditContext; public UpdateConfigurationsCallable(String pid, XmlComponentConfigurations xmlConfigurations, ConfigurationService configurationService) { this.pid = pid; this.xmlConfigurations = xmlConfigurations; this.configurationService = configurationService; this.auditContext = AuditContext.currentOrInternal(); } @Override public Void call() throws Exception { logger.info("Updating configurations"); Thread.currentThread().setName(getClass().getSimpleName()); // // update the configuration try (final Scope scope = AuditContext.openScope(this.auditContext)) { List configImpls = this.xmlConfigurations != null ? this.xmlConfigurations.getConfigurations() : null; if (configImpls == null) { return null; } List configs = new ArrayList<>(); configs.addAll(configImpls); if (this.pid == null) { // update all the configurations provided this.configurationService.updateConfigurations(configs); } else { // update only the configuration with the provided id for (ComponentConfiguration config : configs) { if (this.pid.equals(config.getPid())) { this.configurationService.updateConfiguration(this.pid, config.getConfigurationProperties()); } } } } catch (KuraException e) { logger.error("Error updating configurations: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e); } return null; } } class RollbackCallable implements Callable { private static Logger logger = LoggerFactory.getLogger(RollbackCallable.class); private final Long snapshotId; private final ConfigurationService configurationService; private final AuditContext auditContext; public RollbackCallable(Long snapshotId, ConfigurationService configurationService) { super(); this.snapshotId = snapshotId; this.configurationService = configurationService; this.auditContext = AuditContext.currentOrInternal(); } @Override public Void call() throws Exception { Thread.currentThread().setName(getClass().getSimpleName()); // rollback to the specified snapshot if any try (final Scope scope = AuditContext.openScope(this.auditContext)) { if (this.snapshotId == null) { this.configurationService.rollback(); } else { this.configurationService.rollback(this.snapshotId); } } catch (KuraException e) { logger.error("Error rolling back to snapshot: {}", e); throw new KuraException(KuraErrorCode.CONFIGURATION_ROLLBACK, e); } return null; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ComponentConfigurationImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.Map; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.core.configuration.metatype.Tocd; public class ComponentConfigurationImpl implements ComponentConfiguration { protected String pid; protected Tocd definition; protected Map properties; /** * Default constructor. Does not initialize any of the fields. */ // Required by JAXB public ComponentConfigurationImpl() { } public ComponentConfigurationImpl(String pid, Tocd definition, Map properties) { super(); this.pid = pid; this.definition = definition; this.properties = properties; } @Override public String getPid() { return this.pid; } @Override public Tocd getDefinition() { return this.definition; } @Override public Map getConfigurationProperties() { return this.properties; } public void setPid(String pid) { this.pid = pid; } public void setDefinition(Tocd definition) { this.definition = definition; } public void setProperties(Map properties) { this.properties = properties; } @Override public String toString() { return "ComponentConfigurationImpl [pid=" + this.pid + ", definition=" + this.definition + ", properties=" + this.properties + "]"; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ComponentMetaTypeBundleTracker.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.Map; import org.eclipse.kura.configuration.metatype.Designate; import org.eclipse.kura.configuration.metatype.OCD; import org.eclipse.kura.core.configuration.metatype.Tmetadata; import org.eclipse.kura.core.configuration.metatype.Tocd; import org.eclipse.kura.core.configuration.util.ComponentUtil; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.InvalidSyntaxException; import org.osgi.util.tracker.BundleTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * BundleTracker to track all the Service which have defaults in MetaType. * When the ConfigurableComponet is found it is then registered to the ConfigurationService. */ public class ComponentMetaTypeBundleTracker extends BundleTracker { private static final Logger s_logger = LoggerFactory.getLogger(ComponentMetaTypeBundleTracker.class); private final BundleContext m_context; private final ConfigurationServiceImpl m_configurationService; public ComponentMetaTypeBundleTracker(BundleContext context, ConfigurationServiceImpl configurationService) throws InvalidSyntaxException { super(context, Bundle.ACTIVE, null); this.m_context = context; this.m_configurationService = configurationService; } // ---------------------------------------------------------------- // // Override APIs // // ---------------------------------------------------------------- @Override public Bundle addingBundle(Bundle bundle, BundleEvent event) { Bundle bnd = super.addingBundle(bundle, event); s_logger.debug("addingBundle(): processing MetaType for bundle: {}...", bundle.getSymbolicName()); processBundleMetaType(bundle); s_logger.debug("addingBundle(): processed MetaType for bundle: {}", bundle.getSymbolicName()); return bnd; } @Override public void removedBundle(Bundle bundle, BundleEvent event, Bundle object) { super.removedBundle(bundle, event, object); this.m_configurationService.onBundleRemoved(bundle); } // ---------------------------------------------------------------- // // Private APIs // // ---------------------------------------------------------------- private void processBundleMetaType(Bundle bundle) { // Push the latest configuration merging the properties in ConfigAdmin // with the default properties read from the component's meta-type. // This allows components to incrementally add new configuration // properties in the meta-type. // Only the new default properties are merged with the configuration // properties in ConfigurationAdmin. // Note: configuration properties in snapshots no longer present in // the meta-type are not purged. Map metas = ComponentUtil.getMetadata(this.m_context, bundle); for (String metatypePid : metas.keySet()) { try { // register the OCD for all the contained services Tmetadata metadata = metas.get(metatypePid); if (metadata != null) { // check if this component is a factory boolean isFactory = false; Designate designate = ComponentUtil.getDesignate(metadata, metatypePid); if (designate.getFactoryPid() != null && !designate.getFactoryPid().isEmpty()) { isFactory = true; metatypePid = designate.getFactoryPid(); } // register the pid with the OCD and whether it is a factory OCD ocd = ComponentUtil.getOCD(metadata, metatypePid); this.m_configurationService.registerComponentOCD(metatypePid, (Tocd) ocd, isFactory, bundle); } } catch (Exception e) { s_logger.error("Error seeding configuration for pid: " + metatypePid, e); } } } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurableComponentTracker.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.configuration.SelfConfiguringComponent; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.util.tracker.ServiceTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * ServiceTracker to track all the ConfigurabaleComponents. * When the ConfigurableComponet is found it is then registered to the ConfigurationService. */ @SuppressWarnings("rawtypes") public class ConfigurableComponentTracker extends ServiceTracker { private static final Logger s_logger = LoggerFactory.getLogger(ConfigurableComponentTracker.class); private final ConfigurationServiceImpl m_confService; @SuppressWarnings("unchecked") public ConfigurableComponentTracker(BundleContext context, ConfigurationServiceImpl confService) throws InvalidSyntaxException { // super(context, (String) null, null); // Wrong: throws an exception // super(context, "", null); // Wrong: does not track anything // super(context, "org.eclipse.kura..example.publisher.ExamplePublisher", null); // tracks the specified class // but of course we cannot use this // super(context, (ServiceReference) null, null); // Wrong: throws an exception // super(context, SelfConfiguringComponent.class, null); // Wrong: does not track anything // super(context, context.createFilter("(" + Constants.OBJECTCLASS + // "="+SelfConfiguringComponent.class.getName()+")"), null); // No // super(context, context.createFilter("(" + Constants.SERVICE_EXPORTED_INTERFACES + // "="+SelfConfiguringComponent.class.getName()+")"), null); // Track nothing. Export the interface? // TODO: find a better filter // This works but we track everything super(context, context.createFilter("(" + Constants.OBJECTCLASS + "=*)"), null); this.m_confService = confService; } // ---------------------------------------------------------------- // // Override APIs // // ---------------------------------------------------------------- @SuppressWarnings({ "unchecked" }) @Override public void open(boolean trackAllServices) { s_logger.info("Opening ServiceTracker"); super.open(trackAllServices); try { s_logger.info("Getting ServiceReferences"); ServiceReference[] refs = this.context.getServiceReferences((String) null, null); if (refs != null) { for (ServiceReference ref : refs) { String servicePid = (String) ref.getProperty(Constants.SERVICE_PID); String pid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID); String factoryPid = (String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID); if (servicePid != null) { Object obj = this.context.getService(ref); try { if (obj == null) { s_logger.info("Could not find service for: {}", ref); } else if (obj instanceof ConfigurableComponent) { s_logger.info( "Adding ConfigurableComponent with pid {}, service pid {} and factory pid " + factoryPid, pid, servicePid); this.m_confService.registerComponentConfiguration(pid, servicePid, factoryPid); } else if (obj instanceof SelfConfiguringComponent) { s_logger.info("Adding SelfConfiguringComponent with pid {} and service pid {}", pid, servicePid); this.m_confService.registerSelfConfiguringComponent(pid, servicePid); } } finally { this.context.ungetService(ref); } } } } } catch (InvalidSyntaxException ise) { s_logger.error("Error in addingBundle", ise); } } @SuppressWarnings({ "unchecked" }) @Override public Object addingService(ServiceReference ref) { Object service = super.addingService(ref); String servicePid = (String) ref.getProperty(Constants.SERVICE_PID); String pid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID); String factoryPid = (String) ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID); if (servicePid != null) { if (service instanceof ConfigurableComponent) { s_logger.info("Adding ConfigurableComponent with pid {}, service pid {} and factory pid " + factoryPid, pid, servicePid); this.m_confService.registerComponentConfiguration(pid, servicePid, factoryPid); } else if (service instanceof SelfConfiguringComponent) { s_logger.info("Adding SelfConfiguringComponent with pid {} and service pid {}", pid, servicePid); this.m_confService.registerSelfConfiguringComponent(pid, servicePid); } } return service; } @SuppressWarnings({ "unchecked" }) @Override public void removedService(ServiceReference reference, Object service) { super.removedService(reference, service); String servicePid = (String) reference.getProperty(Constants.SERVICE_PID); String pid = (String) reference.getProperty(ConfigurationService.KURA_SERVICE_PID); if (service instanceof ConfigurableComponent) { s_logger.info("Removed ConfigurableComponent with pid {} and service pid {}", pid, servicePid); this.m_confService.unregisterComponentConfiguration(pid); } else if (service instanceof SelfConfiguringComponent) { s_logger.info("Removed SelfConfiguringComponent with pid {} and service pid {}", pid, servicePid); this.m_confService.unregisterComponentConfiguration(servicePid); } } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationChangeEvent.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.Map; import org.osgi.service.event.Event; public class ConfigurationChangeEvent extends Event { public static final String CONF_CHANGE_EVENT_TOPIC = "org/eclipse/kura/core/configuration/event/CONF_CHANGE_EVENT_TOPIC"; public static final String CONF_CHANGE_EVENT_SESSION_PROP = "session"; public static final String CONF_CHANGE_EVENT_PID_PROP = "pid"; public ConfigurationChangeEvent(Map properties) { super(CONF_CHANGE_EVENT_TOPIC, properties); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceAuditFacade.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.audit.AuditContext; import org.eclipse.kura.configuration.ComponentConfiguration; import org.osgi.framework.Filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ConfigurationServiceAuditFacade extends ConfigurationServiceImpl { private static final String CONFIGURATION_SERVICE_FAILURE = "{} ConfigurationService - Failure - {}"; private static final String CONFIGURATION_SERVICE_SUCCESS = "{} ConfigurationService - Success - {}"; private static final Logger auditLogger = LoggerFactory.getLogger("AuditLogger"); @Override public synchronized void createFactoryConfiguration(String factoryPid, String pid, Map properties, boolean takeSnapshot) throws KuraException { audit(() -> super.createFactoryConfiguration(factoryPid, pid, properties, takeSnapshot), "Create factory configuration " + factoryPid + " " + pid); postConfigurationChangedEvent(pid); } @Override public synchronized void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException { audit(() -> super.deleteFactoryConfiguration(pid, takeSnapshot), "Delete factory configuration: " + pid); postConfigurationChangedEvent(pid); } @Override public List getComponentConfigurations() throws KuraException { return audit(() -> super.getComponentConfigurations(), "Get component configurations"); } @Override public List getComponentConfigurations(Filter filter) throws KuraException { return audit(() -> super.getComponentConfigurations(filter), "Get component configurations: " + filter); } @Override public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException { return audit(() -> super.getComponentConfiguration(pid), "Get component configuration: " + pid); } @Override public synchronized void updateConfiguration(String pid, Map properties) throws KuraException { audit(() -> super.updateConfiguration(pid, properties), "Update configuration: " + pid); postConfigurationChangedEvent(pid); } @Override public synchronized void updateConfiguration(String pid, Map properties, boolean takeSnapshot) throws KuraException { audit(() -> super.updateConfiguration(pid, properties, takeSnapshot), "Update configuration: " + pid); postConfigurationChangedEvent(pid); } @Override public synchronized void updateConfigurations(List configs) throws KuraException { audit(() -> super.updateConfigurations(configs), "Update configurations: " + formatConfigurationPids(configs)); postConfigurationChangedEvent(formatConfigurationPids(configs)); } @Override public synchronized void updateConfigurations(List configs, boolean takeSnapshot) throws KuraException { audit(() -> super.updateConfigurations(configs, takeSnapshot), "Update configurations: " + formatConfigurationPids(configs)); postConfigurationChangedEvent(formatConfigurationPids(configs)); } @Override public List getSnapshot(long sid) throws KuraException { return audit(() -> super.getSnapshot(sid), "Get snapshot: " + sid); } @Override public long snapshot() throws KuraException { postConfigurationChangedEvent(""); return audit(super::snapshot, "Take snapshot"); } @Override public long rollback() throws KuraException { postConfigurationChangedEvent(""); return audit(() -> super.rollback(), "Rollback latest snapshot"); } @Override public synchronized void rollback(long id) throws KuraException { audit(() -> super.rollback(id), "Rollback snapshot: " + id); postConfigurationChangedEvent(""); } private static T audit(final FallibleSupplier task, final String message) throws E { try { final T result = task.get(); auditLogger.info(CONFIGURATION_SERVICE_SUCCESS, AuditContext.currentOrInternal(), message); return result; } catch (final Exception e) { auditLogger.warn(CONFIGURATION_SERVICE_FAILURE, AuditContext.currentOrInternal(), message); throw e; } } private static void audit(final FallibleTask task, final String message) throws E { try { task.run(); auditLogger.info(CONFIGURATION_SERVICE_SUCCESS, AuditContext.currentOrInternal(), message); } catch (final Exception e) { auditLogger.warn(CONFIGURATION_SERVICE_FAILURE, AuditContext.currentOrInternal(), message); throw e; } } private String formatConfigurationPids(final List configs) { return configs.stream().map(ComponentConfiguration::getPid).reduce("", (a, b) -> a + " " + b); } private interface FallibleSupplier { public T get() throws E; } private interface FallibleTask { public void run() throws E; } private void postConfigurationChangedEvent(String pid) { Optional auditContext = AuditContext.current(); if (auditContext.isPresent()) { String sessionId = auditContext.get().getProperties().get("session.id"); Map properties = new HashMap<>(); properties.put(ConfigurationChangeEvent.CONF_CHANGE_EVENT_PID_PROP, pid); properties.put(ConfigurationChangeEvent.CONF_CHANGE_EVENT_SESSION_PROP, sessionId); if (sessionId != null) { this.eventAdmin.postEvent(new ConfigurationChangeEvent(properties)); } } } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.configuration; import static java.util.Objects.isNull; import static java.util.Objects.requireNonNull; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Dictionary; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.SortedSet; import java.util.TreeSet; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraIOException; import org.eclipse.kura.KuraPartialSuccessException; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.configuration.SelfConfiguringComponent; import org.eclipse.kura.configuration.metatype.AD; import org.eclipse.kura.configuration.metatype.OCD; import org.eclipse.kura.configuration.metatype.OCDService; import org.eclipse.kura.configuration.metatype.Scalar; import org.eclipse.kura.core.configuration.metatype.Tocd; import org.eclipse.kura.core.configuration.upgrade.ConfigurationUpgrade; import org.eclipse.kura.core.configuration.util.CollectionsUtil; import org.eclipse.kura.core.configuration.util.ComponentUtil; import org.eclipse.kura.core.configuration.util.StringUtil; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.system.SystemService; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Filter; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.cm.Configuration; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentException; import org.osgi.service.component.runtime.ServiceComponentRuntime; import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; import org.osgi.service.event.EventAdmin; import org.osgi.service.metatype.AttributeDefinition; import org.osgi.service.metatype.MetaTypeService; import org.osgi.service.metatype.ObjectClassDefinition; import org.osgi.util.tracker.BundleTracker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Implementation of ConfigurationService. */ public class ConfigurationServiceImpl implements ConfigurationService, OCDService { private static final String GETTING_CONFIGURATION_ERROR = "Error getting Configuration for component: {}. Ignoring it."; private static final Logger logger = LoggerFactory.getLogger(ConfigurationServiceImpl.class); private static final Pattern SNAPSHOT_FILENAME_PATTERN = Pattern.compile("snapshot_(\\d+)\\.xml"); private ComponentContext ctx; private BundleContext bundleContext; private BundleTracker bundleTracker; @SuppressWarnings("unused") private MetaTypeService metaTypeService; private ConfigurationAdmin configurationAdmin; private SystemService systemService; private CryptoService cryptoService; private ServiceComponentRuntime scrService; private Marshaller xmlMarshaller; private Unmarshaller xmlUnmarshaller; protected EventAdmin eventAdmin; // contains all the PIDs (aka kura.service.pid) - both of configurable and self // configuring components private final Set allActivatedPids; // contains the self configuring components ONLY! private final Set activatedSelfConfigComponents; // maps either service.pid or service.factoryPid to the related OCD private final Map ocds; // contains the service.factoryPid of all Factory Components private final Set factoryPids; // maps the kura.service.pid to the associated service.factoryPid private final Map factoryPidByPid; // contains all the pids (kura.service.pid) which have to be deleted private final Set pendingDeletePids; // maps the kura.service.pid to the associated service.pid private final Map servicePidByPid; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setConfigurationAdmin(ConfigurationAdmin configAdmin) { this.configurationAdmin = configAdmin; } public void setMetaTypeService(MetaTypeService metaTypeService) { this.metaTypeService = metaTypeService; } public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void setScrService(ServiceComponentRuntime scrService) { this.scrService = scrService; } public void setXmlMarshaller(final Marshaller marshaller) { this.xmlMarshaller = marshaller; } public void setXmlUnmarshaller(final Unmarshaller unmarshaller) { this.xmlUnmarshaller = unmarshaller; } public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } public ConfigurationServiceImpl() { this.allActivatedPids = new HashSet<>(); this.activatedSelfConfigComponents = new HashSet<>(); this.pendingDeletePids = new HashSet<>(); this.ocds = new HashMap<>(); this.factoryPids = new HashSet<>(); this.factoryPidByPid = new HashMap<>(); this.servicePidByPid = new HashMap<>(); } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) throws InvalidSyntaxException { logger.info("activate..."); // save the bundle context this.ctx = componentContext; this.bundleContext = componentContext.getBundleContext(); // Load the latest snapshot and push it to ConfigurationAdmin try { loadLatestSnapshotInConfigAdmin(); } catch (Exception e) { throw new ComponentException("Error loading latest snapshot", e); } this.bundleTracker = new ComponentMetaTypeBundleTracker(this.ctx.getBundleContext(), this); this.bundleTracker.open(); } protected void addConfigurableComponent(final ServiceReference reference) { final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID)); if (servicePid == null) { return; } final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID)); final String factoryPid = makeString(reference.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID)); registerComponentConfiguration(kuraPid, servicePid, factoryPid); } protected void removeConfigurableComponent(final ServiceReference reference) { final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID)); if (servicePid == null) { return; } final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID)); unregisterComponentConfiguration(kuraPid); } protected void addSelfConfiguringComponent(final ServiceReference reference) { final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID)); if (servicePid == null) { return; } final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID)); registerSelfConfiguringComponent(kuraPid, servicePid); } protected void removeSelfConfiguringComponent(final ServiceReference reference) { final String servicePid = makeString(reference.getProperty(Constants.SERVICE_PID)); if (servicePid == null) { return; } final String kuraPid = makeString(reference.getProperty(ConfigurationService.KURA_SERVICE_PID)); unregisterComponentConfiguration(kuraPid); } protected void deactivate() { logger.info("deactivate..."); if (this.bundleTracker != null) { this.bundleTracker.close(); this.bundleTracker = null; } } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public Set getConfigurableComponentPids() { if (this.allActivatedPids.isEmpty()) { return Collections.emptySet(); } return Collections.unmodifiableSet(this.allActivatedPids); } // Don't perform internal calls to this method @Override public List getComponentConfigurations() throws KuraException { return getComponentConfigurationsInternal(); } @Override public List getComponentConfigurations(final Filter filter) throws KuraException { if (filter == null) { return getComponentConfigurationsInternal(); } try { final ServiceReference[] refs = this.bundleContext.getAllServiceReferences(null, null); final List result = new ArrayList<>(refs.length); for (final ServiceReference ref : refs) { if (!filter.match(ref)) { continue; } final Object kuraServicePid = ref.getProperty(KURA_SERVICE_PID); if (kuraServicePid instanceof String) { final ComponentConfiguration config = getComponentConfigurationInternal((String) kuraServicePid); if (config != null) { result.add(config); } } } return result; } catch (final Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e); } } // Don't perform internal calls to this method @Override public ComponentConfiguration getComponentConfiguration(String pid) throws KuraException { ComponentConfiguration tempConfig = getComponentConfigurationInternal(pid); if (tempConfig != null && tempConfig.getConfigurationProperties() != null) { decryptConfigurationProperties(tempConfig.getConfigurationProperties()); } return tempConfig; } @Override public synchronized void updateConfiguration(String pidToUpdate, Map propertiesToUpdate) throws KuraException { // don't call this method internally updateConfiguration(pidToUpdate, propertiesToUpdate, true); } @Override public synchronized void updateConfiguration(String pidToUpdate, Map propertiesToUpdate, boolean takeSnapshot) throws KuraException { // don't call this method internally List configs = new ArrayList<>(); ComponentConfigurationImpl cci = new ComponentConfigurationImpl(pidToUpdate, null, propertiesToUpdate); configs.add(cci); updateConfigurations(configs, takeSnapshot); } // Don't perform internal calls to this method @Override public synchronized void updateConfigurations(List configsToUpdate) throws KuraException { updateConfigurations(configsToUpdate, true); } @Override public synchronized void updateConfigurations(List configsToUpdate, boolean takeSnapshot) throws KuraException { // don't call this method internally for (ComponentConfiguration config : configsToUpdate) { if (config != null) { ComponentUtil.encryptConfigurationProperties(config.getConfigurationProperties(), this.cryptoService); } } // only encrypted properties are passed to internal methods updateConfigurationsInternal(configsToUpdate, takeSnapshot); } // ---------------------------------------------------------------- // // Service APIs: Factory Management // // ---------------------------------------------------------------- @Override public Set getFactoryComponentPids() { return Collections.unmodifiableSet( this.factoryPids.stream().map(TrackedComponentFactory::getFactoryPid).collect(Collectors.toSet())); } @Override public ComponentConfiguration getDefaultComponentConfiguration(String pid) throws KuraException { ComponentConfiguration tempConfig = getDefaultComponentConfigurationInternal(pid); if (tempConfig != null && tempConfig.getConfigurationProperties() != null) { decryptConfigurationProperties(tempConfig.getConfigurationProperties()); } return tempConfig; } @Override public void createFactoryConfiguration(String factoryPid, String pid, Map properties, boolean takeSnapshot) throws KuraException { createFactoryConfigurationInternal(factoryPid, pid, ComponentUtil.encryptConfigurationProperties(properties, this.cryptoService, true), takeSnapshot); } private synchronized void createFactoryConfigurationInternal(String factoryPid, String pid, Map properties, boolean takeSnapshot) throws KuraException { if (pid == null) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "pid cannot be null"); } else if (this.servicePidByPid.containsKey(pid)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "pid " + pid + " already exists"); } try { // Second argument in createFactoryConfiguration is a bundle location. If left // null the new bundle location // will be bound to the location of the first bundle that registers a Managed // Service Factory with a // corresponding PID logger.info("Creating new configuration for factory pid {} and pid {}", factoryPid, pid); String servicePid = this.configurationAdmin.createFactoryConfiguration(factoryPid, null).getPid(); logger.info("Updating newly created configuration for pid {}", pid); Map mergedProperties = new HashMap<>(); if (properties != null) { mergedProperties.putAll(properties); } OCD ocd = this.ocds.get(factoryPid); mergeWithDefaults(ocd, mergedProperties); mergedProperties.put(ConfigurationService.KURA_SERVICE_PID, pid); Dictionary dict = CollectionsUtil.mapToDictionary(mergedProperties); Configuration config = this.configurationAdmin.getConfiguration(servicePid, "?"); config.update(dict); registerComponentConfiguration(pid, servicePid, factoryPid); this.pendingDeletePids.remove(pid); if (takeSnapshot) { snapshot(); } } catch (IOException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e, "Cannot create component instance for factory " + factoryPid); } } @Override public synchronized void deleteFactoryConfiguration(String pid, boolean takeSnapshot) throws KuraException { if (pid == null) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "pid cannot be null"); } try { final Configuration[] configurations = this.configurationAdmin.listConfigurations(null); if (configurations == null) { logger.warn("ConfigurationAdmin has no configurations"); return; } final Optional config = Arrays.stream(configurations).filter(c -> { final Object kuraServicePid = c.getProperties().get(KURA_SERVICE_PID); final String factoryPid = c.getFactoryPid(); return pid.equals(kuraServicePid) && factoryPid != null; }).findAny(); if (!config.isPresent()) { logger.warn("The component with kura.service.pid {} does not exist or it is not a Factory Component", pid); return; } logger.info("Deleting factory configuration for component with pid {}...", pid); config.get().delete(); unregisterComponentConfiguration(pid); this.pendingDeletePids.add(pid); if (takeSnapshot) { snapshot(); } logger.info("Deleting factory configuration for component with pid {}...done", pid); } catch (Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e, "Cannot delete component instance " + pid); } } // ---------------------------------------------------------------- // // Service APIs: Snapshot Management // // ---------------------------------------------------------------- @Override public long snapshot() throws KuraException { logger.info("Writing snapshot - Getting component configurations..."); List configs = buildCurrentConfiguration(null); return saveSnapshot(configs); } @Override public long rollback() throws KuraException { // get the second-last most recent snapshot // and rollback to that one. Set ids = getSnapshots(); if (ids.size() < 2) { throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, null, "No Snapshot Available"); } // rollback to the second last snapshot Long[] snapshots = ids.toArray(new Long[] {}); Long id = snapshots[ids.size() - 2]; rollback(id); return id; } @Override public void rollback(long id) throws KuraException { logger.info("Rolling back to snapshot {}...", id); List causes = new ArrayList<>(); final Map snapshotConfigs = getSnapshotConfigs(id); final Map currentConfigs = getCurrentConfigs(); Iterator> currentConfigsIterator = currentConfigs.entrySet().iterator(); while (currentConfigsIterator.hasNext()) { manageCurrentConfigs(causes, snapshotConfigs, currentConfigsIterator); } for (final ComponentConfiguration snapshotConfig : snapshotConfigs.values()) { manageSnapshotConfigs(causes, currentConfigs, snapshotConfig); } this.pendingDeletePids.clear(); if (!causes.isEmpty()) { throw new KuraPartialSuccessException("Rollback", causes); } final SortedSet snapshotIds = getSnapshotsInternal(); if (snapshotIds.isEmpty() || id != snapshotIds.last()) { saveSnapshot(snapshotConfigs.values()); } } @Override public Set getSnapshots() throws KuraException { return getSnapshotsInternal(); } @Override public List getSnapshot(long sid) throws KuraException { List returnConfigs = new ArrayList<>(); XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(sid); if (xmlConfigs != null) { List configs = xmlConfigs.getConfigurations(); for (ComponentConfiguration config : configs) { if (config != null) { try { decryptConfigurationProperties(config.getConfigurationProperties()); } catch (Throwable t) { logger.warn("Error during snapshot password decryption"); } } } returnConfigs.addAll(xmlConfigs.getConfigurations()); } return returnConfigs; } // ---------------------------------------------------------------- // // Package APIs // // ---------------------------------------------------------------- synchronized void registerComponentOCD(String metatypePid, Tocd ocd, boolean isFactory, final Bundle provider) throws KuraException { // metatypePid is either the 'pid' or 'factoryPid' attribute of the MetaType // Designate element // 'pid' matches a service.pid, not a kura.service.pid logger.info("Registering metatype pid: {} ...", metatypePid); this.ocds.put(metatypePid, ocd); if (isFactory) { registerFactoryComponentOCD(metatypePid, ocd, provider); } else { try { updateWithDefaultConfiguration(metatypePid, ocd); } catch (IOException e) { throw new KuraIOException(e); } } } synchronized void onBundleRemoved(final Bundle bundle) { this.factoryPids.removeIf(factory -> { final Bundle provider = factory.getProviderBundle(); return provider.getSymbolicName().equals(bundle.getSymbolicName()) && provider.getVersion().equals(bundle.getVersion()); }); } synchronized void registerComponentConfiguration(final String pid, final String servicePid, final String factoryPid) { if (pid == null || servicePid == null) { logger.warn("Either PID (kura.service.pid) {} or Service PID (service.pid) {} is null", pid, servicePid); return; } if (!this.allActivatedPids.contains(pid)) { // register the component instance logger.info("Registering ConfigurableComponent - {}....", pid); this.servicePidByPid.put(pid, servicePid); if (factoryPid != null) { this.factoryPidByPid.put(pid, factoryPid); Tocd factoryOCD = this.ocds.get(factoryPid); if (factoryOCD != null) { try { updateWithDefaultConfiguration(pid, factoryOCD); } catch (IOException e) { logger.info("Error seeding updated configuration for pid: {}", pid); } } } this.allActivatedPids.add(pid); logger.info("Registering ConfigurableComponent - {}....Done", pid); } } synchronized void registerSelfConfiguringComponent(final String pid, final String servicePid) { if (pid == null) { logger.warn("PID (kura.service.pid) is null"); return; } logger.info("Registering SelfConfiguringComponent - {}....", pid); if (!this.allActivatedPids.contains(pid)) { this.allActivatedPids.add(pid); } if (!this.activatedSelfConfigComponents.contains(pid)) { this.servicePidByPid.put(pid, servicePid); this.activatedSelfConfigComponents.add(pid); } logger.info("Registering SelfConfiguringComponent - {}....Done", pid); } synchronized void unregisterComponentConfiguration(String pid) { if (pid == null) { logger.warn("pid is null"); return; } logger.info("Removing component configuration for pid {}", pid); this.servicePidByPid.remove(pid); this.factoryPidByPid.remove(pid); this.activatedSelfConfigComponents.remove(pid); this.allActivatedPids.remove(pid); } boolean mergeWithDefaults(OCD ocd, Map properties) { boolean changed = false; Set keys = properties.keySet(); Map defaults = getDefaultProperties(ocd); Set defaultsKeys = defaults.keySet(); defaultsKeys.removeAll(keys); if (!defaultsKeys.isEmpty()) { changed = true; logger.info("Merging configuration for pid: {}", ocd.getId()); for (String key : defaultsKeys) { Object value = defaults.get(key); properties.put(key, value); logger.debug("Merged configuration properties with property with name: {} and default value {}", key, value); } } return changed; } Map getDefaultProperties(OCD ocd) { return ComponentUtil.getDefaultProperties(ocd, this.ctx); } void decryptConfigurationProperties(Map configProperties) { for (Entry property : configProperties.entrySet()) { Object configValue = property.getValue(); if (configValue instanceof Password || configValue instanceof Password[]) { Object decryptedValue; try { decryptedValue = decryptPasswordProperties(configValue); configProperties.put(property.getKey(), decryptedValue); } catch (KuraException e) { logger.error("Failed to decrypt password properties", e); } } } } private Object decryptPasswordProperties(Object encryptedValue) throws KuraException { Object decryptedValue = null; if (encryptedValue instanceof Password) { decryptedValue = decryptPassword((Password) encryptedValue); } else if (encryptedValue instanceof Password[]) { Password[] encryptedPasswords = (Password[]) encryptedValue; Password[] decryptedPasswords = new Password[encryptedPasswords.length]; for (int i = 0; i < encryptedPasswords.length; i++) { decryptedPasswords[i] = decryptPassword(encryptedPasswords[i]); } decryptedValue = decryptedPasswords; } return decryptedValue; } private Password decryptPassword(Password encryptedPassword) throws KuraException { return new Password(this.cryptoService.decryptAes(encryptedPassword.getPassword())); } // ---------------------------------------------------------------- // // Private APIs // // ---------------------------------------------------------------- private synchronized void updateConfigurationsInternal(List configsToUpdate, boolean takeSnapshot) throws KuraException { List causes = new ArrayList<>(); List configs = buildCurrentConfiguration(configsToUpdate); updateConfigurationInternal(configsToUpdate, configs, causes); // this step creates any not yet existing factory configuration present in // configsToUpdate for (ComponentConfiguration config : configsToUpdate) { String factoryPid = null; final Map properties = config.getConfigurationProperties(); if (properties != null) { factoryPid = (String) properties.get(ConfigurationAdmin.SERVICE_FACTORYPID); } if (factoryPid != null && !this.allActivatedPids.contains(config.getPid())) { ConfigurationUpgrade.upgrade(config, this.bundleContext); String pid = config.getPid(); logger.info("Creating configuration with pid: {} and factory pid: {}", pid, factoryPid); try { createFactoryConfigurationInternal(factoryPid, pid, properties, false); configs.add(config); } catch (KuraException e) { logger.warn("Error creating configuration with pid: {} and factory pid: {}", pid, factoryPid, e); } } } if (takeSnapshot && configs != null && !configs.isEmpty()) { saveSnapshot(configs); } if (!causes.isEmpty()) { throw new KuraPartialSuccessException("updateConfigurations", causes); } } private void updateConfigurationInternal(List configsToUpdate, List configs, List causes) { for (ComponentConfiguration config : configs) { for (ComponentConfiguration configToUpdate : configsToUpdate) { if (config.getPid().equals(configToUpdate.getPid())) { try { updateConfigurationInternal(config.getPid(), config.getConfigurationProperties(), false); } catch (KuraException e) { logger.warn("Error during updateConfigurations for component " + config.getPid(), e); causes.add(e); } break; } } } } // returns configurations with encrypted passwords private List getComponentConfigurationsInternal() throws KuraException { List configs = new ArrayList<>(); // assemble all the configurations we have // clone the list to avoid concurrent modifications List allPids = new ArrayList<>(this.allActivatedPids); for (String pid : allPids) { try { ComponentConfiguration cc = getComponentConfigurationInternal(pid); if (cc != null) { configs.add(cc); } } catch (Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e, "Error getting configuration for component " + pid); } } return configs; } // returns configurations with encrypted passwords private ComponentConfiguration getComponentConfigurationInternal(String pid) { ComponentConfiguration cc; if (!this.activatedSelfConfigComponents.contains(pid)) { cc = getConfigurableComponentConfiguration(pid); } else { cc = getSelfConfiguringComponentConfiguration(pid); } return cc; } private ComponentConfiguration getDefaultComponentConfigurationInternal(String pid) { ComponentConfiguration cc; if (!this.activatedSelfConfigComponents.contains(pid)) { cc = getConfigurableComponentDefaultConfiguration(pid); } else { cc = getSelfConfiguringComponentDefaultConfiguration(pid); } return cc; } private ComponentConfiguration getConfigurableComponentDefaultConfiguration(String pid) { Tocd ocd = getOCDForPid(pid); Map props = ComponentUtil.getDefaultProperties(ocd, this.ctx); return new ComponentConfigurationImpl(pid, ocd, props); } private ComponentConfiguration getSelfConfiguringComponentDefaultConfiguration(String pid) { ComponentConfiguration cc = null; try { String filter = String.format("(kura.service.pid=%s)", pid); ServiceReference[] refs = this.ctx.getBundleContext().getServiceReferences((String) null, filter); if (refs != null && refs.length > 0) { ServiceReference ref = refs[0]; Object obj = this.ctx.getBundleContext().getService(ref); try { cc = getSelfConfiguringComponentDefaultConfigurationInternal(obj, pid); } finally { this.ctx.getBundleContext().ungetService(ref); } } } catch (InvalidSyntaxException e) { logger.error(GETTING_CONFIGURATION_ERROR, pid, e); } return cc; } private ComponentConfiguration getSelfConfiguringComponentDefaultConfigurationInternal(Object obj, String pid) { ComponentConfiguration cc = null; if (obj instanceof SelfConfiguringComponent) { SelfConfiguringComponent selfConfigComp = (SelfConfiguringComponent) obj; try { ComponentConfiguration tempCc = selfConfigComp.getConfiguration(); if (tempCc.getPid() == null || !tempCc.getPid().equals(pid)) { logger.error( "Invalid pid for returned Configuration of SelfConfiguringComponent with pid: {} Ignoring it.", pid); return cc; } OCD ocd = tempCc.getDefinition(); if (ocd != null) { Map props = ComponentUtil.getDefaultProperties(ocd, this.ctx); cc = new ComponentConfigurationImpl(pid, (Tocd) ocd, props); } } catch (KuraException e) { logger.error(GETTING_CONFIGURATION_ERROR, pid, e); } } else { logger.error("Component {} is not a SelfConfiguringComponent. Ignoring it.", obj); } return cc; } private void updateWithDefaultConfiguration(String pid, Tocd ocd) throws IOException { String servicePid = this.servicePidByPid.get(pid); if (servicePid == null) { servicePid = pid; } Configuration config = this.configurationAdmin.getConfiguration(servicePid, "?"); if (config != null) { // get the properties from ConfigurationAdmin if any are present Map props = new HashMap<>(); if (config.getProperties() != null) { props.putAll(CollectionsUtil.dictionaryToMap(config.getProperties(), ocd)); } if (!props.containsKey(ConfigurationService.KURA_SERVICE_PID)) { props.put(ConfigurationService.KURA_SERVICE_PID, pid); } // merge the current properties, if any, with the defaults from metatype mergeWithDefaults(ocd, props); config.update(CollectionsUtil.mapToDictionary(props)); logger.info("Seeding updated configuration for pid: {}", pid); } } private void registerFactoryComponentOCD(String metatypePid, Tocd ocd, final Bundle provider) throws KuraException { this.factoryPids.add(new TrackedComponentFactory(metatypePid, provider)); for (Map.Entry entry : this.factoryPidByPid.entrySet()) { if (entry.getValue().equals(metatypePid) && this.servicePidByPid.get(entry.getKey()) != null) { try { updateWithDefaultConfiguration(entry.getKey(), ocd); } catch (IOException e) { throw new KuraIOException(e); } } } } private boolean allSnapshotsAreUnencrypted() { Set snapshotIDs; try { snapshotIDs = getSnapshots(); } catch (KuraException e) { return false; } for (Long snapshot : snapshotIDs) { try { loadEncryptedSnapshotFileContent(snapshot); return false; } catch (Exception e) { // Do nothing... } } return true; } private static String readFully(final File file) throws IOException { final char[] buf = new char[4096]; final StringBuilder builder = new StringBuilder(); try (final FileReader r = new FileReader(file)) { int rd; while ((rd = r.read(buf, 0, buf.length)) > 0) { builder.append(buf, 0, rd); } } return builder.toString(); } private void encryptPlainSnapshots() throws KuraException, IOException { Set snapshotIDs = getSnapshots(); if (snapshotIDs == null || snapshotIDs.isEmpty()) { return; } Long[] snapshots = snapshotIDs.toArray(new Long[] {}); for (Long snapshot : snapshots) { File fSnapshot = getSnapshotFile(snapshot); if (fSnapshot == null || !fSnapshot.exists()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, snapshot); } final XmlComponentConfigurations xmlConfigs = unmarshal(new FileInputStream(fSnapshot), XmlComponentConfigurations.class); ComponentUtil.encryptConfigs(xmlConfigs.getConfigurations(), this.cryptoService); // Writes an encrypted snapshot with encrypted passwords. writeSnapshot(snapshot, xmlConfigs); } } private long saveSnapshot(Collection configs) throws KuraException { List configsToSave = configs.stream() .map(cc -> new ComponentConfigurationImpl(cc.getPid(), null, cc.getConfigurationProperties())) .collect(Collectors.toList()); // Build the XML structure XmlComponentConfigurations conf = new XmlComponentConfigurations(); conf.setConfigurations(configsToSave); // Write it to disk: marshall long sid = new Date().getTime(); // Do not save the snapshot in the past SortedSet snapshotIDs = (SortedSet) getSnapshots(); if (snapshotIDs != null && !snapshotIDs.isEmpty()) { Long lastestID = snapshotIDs.last(); if (lastestID != null && sid <= lastestID) { logger.warn("Snapshot ID: {} is in the past. Adjusting ID to: {} + 1", sid, lastestID); sid = lastestID + 1; } } // Write snapshot writeSnapshot(sid, conf); // Garbage Collector for number of Snapshots Saved garbageCollectionOldSnapshots(); return sid; } private void writeSnapshot(long sid, XmlComponentConfigurations conf) throws KuraException { File fSnapshot = getSnapshotFile(sid); if (fSnapshot == null) { throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND); } File tempSnapshotFile = getTempSnapshotFile(fSnapshot); try { storeSnapshotData(conf, fSnapshot, tempSnapshotFile); finalizeSnapshotWrite(fSnapshot, tempSnapshotFile); } finally { if (tempSnapshotFile.exists()) { try { Files.delete(tempSnapshotFile.toPath()); } catch (IOException e) { logger.warn("Failed to delete temporary snapshot file: {}", tempSnapshotFile.getAbsolutePath(), e); } } } } private void finalizeSnapshotWrite(File fSnapshot, File tempSnapshotFile) throws KuraIOException { try { setSnapshotFilePermissions(fSnapshot, tempSnapshotFile); // Consolidate snapshot writing Files.move(tempSnapshotFile.toPath(), fSnapshot.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } catch (IOException e) { throw new KuraIOException(e); } } private void setSnapshotFilePermissions(File fSnapshot, File tempSnapshotFile) throws IOException { try { Set perms = PosixFilePermissions.fromString("rw-------"); Files.setPosixFilePermissions(tempSnapshotFile.toPath(), perms); } catch (UnsupportedOperationException e1) { // POSIX permissions not supported on this file system, log and continue logger.warn("Unable to set POSIX file permissions for snapshot file: {}", fSnapshot.getAbsolutePath(), e1); } } private void storeSnapshotData(XmlComponentConfigurations conf, File fSnapshot, File tempSnapshotFile) throws KuraException { // Write the temporary snapshot try (FileOutputStream fos = new FileOutputStream(tempSnapshotFile); OutputStream encryptedStream = this.cryptoService.aesEncryptingStream(fos)) { logger.info("Writing snapshot - Saving {}...", fSnapshot.getAbsolutePath()); marshal(encryptedStream, conf); encryptedStream.flush(); fos.flush(); fos.getFD().sync(); logger.info("Writing snapshot - Saving {}... Done.", fSnapshot.getAbsolutePath()); } catch (IOException e) { throw new KuraIOException(e); } } private File getTempSnapshotFile(File fSnapshot) throws KuraIOException { File tempSnapshotFile; try { tempSnapshotFile = File.createTempFile(fSnapshot.getName(), null, new File(fSnapshot.getParent())); } catch (IOException ex) { throw new KuraIOException(ex); } return tempSnapshotFile; } private ComponentConfiguration getConfigurableComponentConfiguration(String pid) { ComponentConfiguration cc = null; try { Tocd ocd = getOCDForPid(pid); String servicePid = this.servicePidByPid.get(pid); if (servicePid != null) { Configuration cfg = this.configurationAdmin.getConfiguration(servicePid, "?"); Map props = CollectionsUtil.dictionaryToMap(cfg.getProperties(), ocd); cc = new ComponentConfigurationImpl(pid, ocd, props); } } catch (Exception e) { logger.error("Error getting Configuration for component: " + pid + ". Ignoring it.", e); } return cc; } private ComponentConfiguration getSelfConfiguringComponentConfiguration(String pid) { ComponentConfiguration cc = null; final ServiceReference[] refs = ServiceUtil.getServiceReferences(this.bundleContext, SelfConfiguringComponent.class, null); try { for (ServiceReference ref : refs) { String ppid = (String) ref.getProperty(KURA_SERVICE_PID); final SelfConfiguringComponent selfConfigComp = (SelfConfiguringComponent) this.bundleContext .getService(ref); if (pid.equals(ppid)) { cc = selfConfigComp.getConfiguration(); if (!isValidSelfConfiguringComponent(pid, cc)) { return null; } } } } catch (KuraException e) { logger.error(GETTING_CONFIGURATION_ERROR, pid, e); } finally { ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } return cc; } private boolean isValidSelfConfiguringComponent(String pid, ComponentConfiguration cc) { if (isNull(cc) || cc.getPid() == null || !cc.getPid().equals(pid)) { logger.error( "Invalid pid for returned Configuration of SelfConfiguringComponent with pid: {}. Ignoring it.", pid); return false; } OCD ocd = cc.getDefinition(); if (isNull(ocd) || isNull(ocd.getAD())) { return false; } List ads = ocd.getAD(); for (AD ad : ads) { String adId = ad.getId(); String adType = ad.getType().value(); if (isNull(adId) || isNull(adType)) { logger.error( "null required type for AD id: {} for returned Configuration of SelfConfiguringComponent with pid: {}", adId, pid); return false; } Map props = cc.getConfigurationProperties(); if (!isNull(props) && !isNull(props.get(adId)) && !isMatchingADType(pid, adId, adType, props.get(adId))) { return false; } } return true; } private boolean isMatchingADType(String pid, String adId, String adType, Object value) { boolean result = false; try { logger.debug("pid: {}, property name: {}, value: {}", pid, adId, value); Scalar propertyScalar = getScalarFromObject(value); Scalar adScalar = Scalar.fromValue(adType); if (propertyScalar != adScalar) { logger.error( "Type: {} for property named: {} does not match the AD type: {} for returned Configuration of SelfConfiguringComponent with pid: {}", propertyScalar.name(), adId, adType, pid); } result = true; } catch (IllegalArgumentException e) { logger.error( "Invalid class for property named: {} for returned Configuration of SelfConfiguringComponent with pid: {}", adId, pid); } return result; } private Scalar getScalarFromObject(Object p) { Class clazz = p.getClass(); if (clazz.isArray()) { Object[] tempArray = (Object[]) p; if (tempArray.length > 0 && tempArray[0] != null) { clazz = tempArray[0].getClass(); } else { clazz = clazz.getComponentType(); } } return Scalar.fromValue(clazz.getSimpleName()); } private TreeSet getSnapshotsInternal() { // keeps the list of snapshots ordered TreeSet ids = new TreeSet<>(); String configDir = getSnapshotsDirectory(); if (configDir != null) { File fConfigDir = new File(configDir); File[] files = fConfigDir.listFiles(); if (files != null) { for (File file : files) { Matcher m = SNAPSHOT_FILENAME_PATTERN.matcher(file.getName()); if (m.matches()) { ids.add(Long.parseLong(m.group(1))); } } } } return ids; } String getSnapshotsDirectory() { return this.systemService.getKuraSnapshotsDirectory(); } private File getSnapshotFile(long id) { String configDir = getSnapshotsDirectory(); if (configDir == null) { return null; } StringBuilder sbSnapshot = new StringBuilder(configDir); sbSnapshot.append(File.separator).append("snapshot_").append(id).append(".xml"); String snapshot = sbSnapshot.toString(); return new File(snapshot); } private void garbageCollectionOldSnapshots() { // get the current snapshots and compared with the maximum number we // need to keep TreeSet sids = getSnapshotsInternal(); int currCount = sids.size(); int maxCount = this.systemService.getKuraSnapshotsCount(); while (currCount > maxCount && !sids.isEmpty()) { // stop if count reached or no more snapshots remain // preserve snapshot ID 0 as this will be considered the seeding // one. long sid = sids.pollFirst(); File fSnapshot = getSnapshotFile(sid); if (sid == 0 || fSnapshot == null) { continue; } Path fSnapshotPath = fSnapshot.toPath(); try { if (Files.deleteIfExists(fSnapshotPath)) { logger.info("Snapshots Garbage Collector. Deleted {}", fSnapshotPath); currCount--; } } catch (IOException e) { logger.warn("Snapshots Garbage Collector. Deletion failed for {}", fSnapshotPath, e); } } } private void loadLatestSnapshotInConfigAdmin() throws KuraException { // // save away initial configuration List configs = buildCurrentConfiguration(null); if (configs == null) { return; } for (ComponentConfiguration config : configs) { if (config != null) { Map props = config.getConfigurationProperties(); if (props != null) { String factoryPid = (String) props.get(ConfigurationAdmin.SERVICE_FACTORYPID); if (factoryPid != null) { createFactoryConfigurationInternal(factoryPid, config.getPid(), props, false); } else { loadConfiguration(config, props); } } } } } private void loadConfiguration(ComponentConfiguration config, Map props) { try { logger.debug("Pushing config to config admin: {}", config.getPid()); // push it to the ConfigAdmin Configuration cfg = this.configurationAdmin.getConfiguration(config.getPid(), "?"); // set kura.service.pid if missing Map newProperties = new HashMap<>(props); if (!newProperties.containsKey(ConfigurationService.KURA_SERVICE_PID)) { newProperties.put(ConfigurationService.KURA_SERVICE_PID, config.getPid()); } cfg.update(CollectionsUtil.mapToDictionary(newProperties)); } catch (IOException e) { logger.warn("Error seeding initial properties to ConfigAdmin for pid: {}", config.getPid(), e); } } private List loadLatestSnapshotConfigurations() throws KuraException { // // Get the latest snapshot file to use as initialization Set snapshotIDs = getSnapshots(); if (snapshotIDs == null || snapshotIDs.isEmpty()) { return Collections.emptyList(); } Long[] snapshots = snapshotIDs.toArray(new Long[] {}); Long lastestID = snapshots[snapshotIDs.size() - 1]; // // Unmarshall logger.info("Loading init configurations from: {}...", lastestID); List configs = null; try { XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(lastestID); if (xmlConfigs != null) { configs = xmlConfigs.getConfigurations(); } } catch (Exception e) { logger.info("Unable to decrypt snapshot! Fallback to unencrypted snapshots mode."); try { if (allSnapshotsAreUnencrypted()) { encryptPlainSnapshots(); configs = loadLatestSnapshotConfigurations(); } } catch (Exception ex) { throw new KuraIOException(ex); } } return configs; } XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) throws KuraException { File fSnapshot = getSnapshotFile(snapshotID); if (fSnapshot == null || !fSnapshot.exists()) { throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND, fSnapshot != null ? fSnapshot.getAbsolutePath() : "null"); } InputStream decryptedStream = null; try { decryptedStream = this.cryptoService.aesDecryptingStream(new FileInputStream(fSnapshot)); } catch (FileNotFoundException e) { logger.error("Error loading file from disk", e); return null; } XmlComponentConfigurations xmlConfigs = null; try { xmlConfigs = unmarshal(decryptedStream, XmlComponentConfigurations.class); } catch (KuraException e) { logger.warn("Error parsing xml", e); } return xmlConfigs; } private void updateConfigurationInternal(String pid, Map properties, boolean snapshotOnConfirmation) throws KuraException { logger.debug("Attempting update configuration for {}", pid); if (!this.allActivatedPids.contains(pid)) { logger.info("UpdatingConfiguration ignored as ConfigurableComponent {} is NOT tracked.", pid); return; } if (properties == null) { logger.info("UpdatingConfiguration ignored as properties for ConfigurableComponent {} are NULL.", pid); return; } // get the OCD from the registered ConfigurableComponents OCD registerdOCD = getRegisteredOCD(pid); if (registerdOCD == null) { logger.info("UpdatingConfiguration ignored as OCD for pid {} cannot be found.", pid); return; } Map mergedProperties = new HashMap<>(); mergeWithDefaults(registerdOCD, mergedProperties); if (!this.activatedSelfConfigComponents.contains(pid)) { try { // get the current running configuration for the selected component Configuration config = this.configurationAdmin.getConfiguration(this.servicePidByPid.get(pid), "?"); Map runningProps = CollectionsUtil.dictionaryToMap(config.getProperties(), registerdOCD); mergedProperties.putAll(runningProps); } catch (IOException e) { logger.info("merge with running failed!"); throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e, pid); } } mergedProperties.putAll(properties); if (!mergedProperties.containsKey(ConfigurationService.KURA_SERVICE_PID)) { mergedProperties.put(ConfigurationService.KURA_SERVICE_PID, pid); } try { updateComponentConfiguration(pid, mergedProperties, snapshotOnConfirmation); logger.info("Updating Configuration of ConfigurableComponent {} ... Done.", pid); } catch (IOException e) { throw new KuraException(KuraErrorCode.CONFIGURATION_UPDATE, e, pid); } } private void updateComponentConfiguration(String pid, Map mergedProperties, boolean snapshotOnConfirmation) throws KuraException, IOException { if (!this.activatedSelfConfigComponents.contains(pid)) { // load the ocd to do the validation BundleContext bundleCtx = this.ctx.getBundleContext(); // FIXME: why the returned ocd is always null? ObjectClassDefinition ocd = ComponentUtil.getObjectClassDefinition(bundleCtx, this.servicePidByPid.get(pid)); // Validate the properties to be applied and set them validateProperties(pid, ocd, mergedProperties); } else { // FIXME: validation of properties for self-configuring // components } // Update the new properties // use ConfigurationAdmin to do the update Configuration config = this.configurationAdmin.getConfiguration(this.servicePidByPid.get(pid), "?"); config.update(CollectionsUtil.mapToDictionary(mergedProperties)); if (snapshotOnConfirmation) { snapshot(); } } private OCD getRegisteredOCD(String pid) { // try to get the OCD from the registered ConfigurableComponents OCD registeredOCD = getOCDForPid(pid); // otherwise try to get it from the registered SelfConfiguringComponents if (registeredOCD == null) { ComponentConfiguration config = getSelfConfiguringComponentConfiguration(pid); if (config != null) { registeredOCD = config.getDefinition(); } } return registeredOCD; } private void validateProperties(String pid, ObjectClassDefinition ocd, Map updatedProps) throws KuraException { if (ocd == null) { return; } // build a map of all the attribute definitions List definitions = Arrays.asList(ocd.getAttributeDefinitions(ObjectClassDefinition.ALL)); Map attributeDefinitions = definitions.stream() .collect(Collectors.toMap(AttributeDefinition::getID, Function.identity())); // loop over the proposed property values // and validate them against the definition for (Entry property : updatedProps.entrySet()) { String key = property.getKey(); AttributeDefinition attributeDefinition = attributeDefinitions.get(key); if (attributeDefinition == null) { // For the attribute for which we do not have a definition, just accept them. continue; } validateAttribute(property, attributeDefinition); } // make sure all required properties are set OCD ocdFull = getOCDForPid(pid); if (ocdFull != null) { for (AD attrDef : ocdFull.getAD()) { // to the required attributes make sure a value is defined. if (attrDef.isRequired() && updatedProps.get(attrDef.getId()) == null) { // if the default one is not defined, throw exception. throw new KuraException(KuraErrorCode.CONFIGURATION_REQUIRED_ATTRIBUTE_MISSING, attrDef.getId()); } } } } private void validateAttribute(Entry property, AttributeDefinition attributeDefinition) throws KuraException { // validate the attribute value String stringValue = StringUtil.valueToString(property.getValue()); if (stringValue != null) { String result = attributeDefinition.validate(stringValue); if (result != null && !result.isEmpty()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, attributeDefinition.getID(), stringValue, result); } } } private synchronized List buildCurrentConfiguration( List configsToUpdate) throws KuraException { List result = new ArrayList<>(); mergeConfigurations(configsToUpdate, result); addSnapshotConfigurations(result); // remove configurations being deleted for (String deletedPid : this.pendingDeletePids) { for (ComponentConfiguration config : result) { if (config.getPid().equals(deletedPid)) { result.remove(config); break; } } } for (final ComponentConfiguration config : result) { ConfigurationUpgrade.upgrade(config, this.bundleContext); } return result; } private void addSnapshotConfigurations(List result) throws KuraException { // complete the returned configurations adding the snapshot configurations // of those components not yet in the list. List snapshotConfigs = loadLatestSnapshotConfigurations(); if (snapshotConfigs != null && !snapshotConfigs.isEmpty()) { for (ComponentConfiguration snapshotConfig : snapshotConfigs) { boolean found = false; for (ComponentConfiguration config : result) { if (config.getPid().equals(snapshotConfig.getPid())) { found = true; break; } } if (!found) { // Add old configurations (or not yet tracked ones) present result.add(snapshotConfig); } } } } private void mergeConfigurations(List configsToUpdate, List result) throws KuraException { // Merge the current configuration of registered components with the provided // configurations. // It is assumed that the PIDs in the provided configurations is a subset of the // registered PIDs. List currentConfigs = getComponentConfigurationsInternal(); if (configsToUpdate == null || configsToUpdate.isEmpty()) { result.addAll(currentConfigs); return; } for (ComponentConfiguration currentConfig : currentConfigs) { // add new configuration obtained by merging its properties with the ones // provided ComponentConfiguration cc = currentConfig; String pid = currentConfig.getPid(); for (ComponentConfiguration configToUpdate : configsToUpdate) { if (configToUpdate.getPid().equals(pid)) { Map props = getAllProperties(currentConfig, configToUpdate); cc = new ComponentConfigurationImpl(pid, (Tocd) configToUpdate.getDefinition(), props); break; } } result.add(cc); } } private Map getAllProperties(ComponentConfiguration currentConfig, ComponentConfiguration configToUpdate) { Map props = new HashMap<>(); if (currentConfig.getConfigurationProperties() != null) { props.putAll(currentConfig.getConfigurationProperties()); } if (configToUpdate.getConfigurationProperties() != null) { props.putAll(configToUpdate.getConfigurationProperties()); } return props; } private Tocd getOCDForPid(String pid) { Tocd ocd = this.ocds.get(this.factoryPidByPid.get(pid)); if (ocd == null) { ocd = this.ocds.get(pid); } return ocd; } /** * Convert property value to string * * @param value * the input value * @return the string property value, or {@code null} */ private static String makeString(Object value) { if (value == null) { return null; } if (value instanceof String) { return (String) value; } return value.toString(); } @Override public List getFactoryComponentOCDs() { return this.factoryPids.stream().map(factory -> { final String factoryPid = factory.getFactoryPid(); return new ComponentConfigurationImpl(factoryPid, this.ocds.get(factoryPid), new HashMap<>()); }).collect(Collectors.toList()); } private ComponentConfiguration getComponentDefinition(String pid) { final Tocd ocd = this.ocds.get(pid); Map defaultProperties = new HashMap<>(); if (ocd != null) { try { defaultProperties = ComponentUtil.getDefaultProperties(ocd, this.ctx); } catch (Exception e) { logger.warn("Failed to get default properties for component: {}", pid, e); } } return new ComponentConfigurationImpl(pid, ocd, defaultProperties); } @Override public ComponentConfiguration getFactoryComponentOCD(String factoryPid) { if (!this.factoryPids.contains(new TrackedComponentFactory(factoryPid, null))) { return null; } return getComponentDefinition(factoryPid); } private static boolean implementsAnyService(ComponentDescriptionDTO component, String[] classes) { final String[] services = component.serviceInterfaces; if (services == null) { return false; } for (String className : classes) { for (String s : services) { if (s.equals(className)) { return true; } } } return false; } @Override public List getServiceProviderOCDs(String... classNames) { return this.scrService.getComponentDescriptionDTOs().stream() .filter(component -> implementsAnyService(component, classNames)).map(c -> c.name) .map(this::getComponentDefinition).filter(Objects::nonNull).collect(Collectors.toList()); } @Override public List getServiceProviderOCDs(Class... classes) { final String[] classNames = new String[classes.length]; for (int i = 0; i < classes.length; i++) { classNames[i] = classes[i].getName(); } return getServiceProviderOCDs(classNames); } protected T unmarshal(final InputStream input, final Class clazz) throws KuraException { try { return requireNonNull(this.xmlUnmarshaller.unmarshal(input, clazz)); } catch (final Exception e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, "configuration", e); } } protected void marshal(final OutputStream out, final Object object) throws KuraException { try { this.xmlMarshaller.marshal(out, object); } catch (Exception e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, "configuration", e); } } private void manageSnapshotConfigs(List causes, final Map currentConfigs, final ComponentConfiguration snapshotConfig) { final Optional optionalCurrentConfig = Optional .ofNullable(currentConfigs.get(snapshotConfig.getPid())); try { logger.info("Processing configuration rollback for component with pid {}...", snapshotConfig.getPid()); rollbackConfigurationInternal(snapshotConfig, optionalCurrentConfig); } catch (IOException e) { logger.warn("Failed to rollback configuration for pid {}", snapshotConfig.getPid(), e); causes.add(e); } } private void manageCurrentConfigs(List causes, final Map snapshotConfigs, Iterator> currentConfigsIterator) { final Entry currentConfigEntry = currentConfigsIterator.next(); final Optional optionalSnapshotConfig = Optional .ofNullable(snapshotConfigs.get(currentConfigEntry.getKey())); if (!isFactoryComponent(currentConfigEntry)) { if (!optionalSnapshotConfig.isPresent() && this.allActivatedPids.contains(currentConfigEntry.getKey())) { try { rollbackToDefaultConfig(currentConfigEntry); } catch (IOException e) { logger.warn("Failed to revert to factory configuration {}", currentConfigEntry.getKey(), e); causes.add(e); } } } else if (!optionalSnapshotConfig.isPresent() || !Objects.equals(currentConfigEntry.getValue().getFactoryPid(), optionalSnapshotConfig.get().getConfigurationProperties().get(ConfigurationAdmin.SERVICE_FACTORYPID))) { try { deleteFactoryComponent(currentConfigsIterator, currentConfigEntry); } catch (IOException e) { logger.warn("Failed to delete configuration {}", currentConfigEntry.getKey(), e); causes.add(e); } } } private void rollbackConfigurationInternal(final ComponentConfiguration snapshotConfig, final Optional existingConfig) throws IOException { final Optional factoryPid = Optional .ofNullable(snapshotConfig.getConfigurationProperties().get(ConfigurationAdmin.SERVICE_FACTORYPID)) .filter(String.class::isInstance).map(String.class::cast); final Map result = snapshotConfig.getConfigurationProperties(); final Optional ocd = Optional.ofNullable(getRegisteredOCD(snapshotConfig.getPid())); if (ocd.isPresent()) { mergeWithDefaults(ocd.get(), result); } final Dictionary resultAsDictionary = CollectionsUtil.mapToDictionary(result); resultAsDictionary.put(KURA_SERVICE_PID, snapshotConfig.getPid()); resultAsDictionary.remove(Constants.SERVICE_PID); final Configuration target; if (existingConfig.isPresent()) { target = existingConfig.get(); } else if (factoryPid.isPresent()) { logger.info("Creating new factory configuration for pid {} and factory pid {}", snapshotConfig.getPid(), factoryPid.get()); target = this.configurationAdmin.createFactoryConfiguration(factoryPid.get(), null); } else { logger.info("Creating new configuration for pid {}", snapshotConfig.getPid()); target = this.configurationAdmin.getConfiguration(snapshotConfig.getPid()); } final Dictionary currentProperties = target.getProperties(); if (currentProperties != null) { currentProperties.remove(Constants.SERVICE_PID); } if (!CollectionsUtil.equals(resultAsDictionary, currentProperties)) { logger.info("Updating configuration for pid {}", snapshotConfig.getPid()); target.update(resultAsDictionary); if (factoryPid.isPresent()) { registerComponentConfiguration(snapshotConfig.getPid(), target.getPid(), factoryPid.get()); } } else { logger.info("No need to update configuration for pid {}", snapshotConfig.getPid()); } } private void deleteFactoryComponent(Iterator> currentConfigsIterator, final Entry currentConfigEntry) throws IOException { logger.info("Deleting factory configuration for component with pid {}...", currentConfigEntry.getKey()); currentConfigEntry.getValue().delete(); currentConfigsIterator.remove(); unregisterComponentConfiguration(currentConfigEntry.getKey()); } private void rollbackToDefaultConfig(final Entry currentConfigEntry) throws IOException { logger.info("Rolling back to default configuration for component pid: '{}'", currentConfigEntry.getKey()); rollbackConfigurationInternal( new ComponentConfigurationImpl(currentConfigEntry.getKey(), null, new HashMap<>()), Optional.of(currentConfigEntry.getValue())); } private boolean isFactoryComponent(final Entry currentConfigEntry) { return currentConfigEntry.getValue().getFactoryPid() != null; } private Map getCurrentConfigs() throws KuraException { Map currentConfigs = new HashMap<>(); try { Configuration[] currentKuraServiceConfigs = this.configurationAdmin .listConfigurations("(" + KURA_SERVICE_PID + "=*)"); if (currentKuraServiceConfigs != null) { currentConfigs = Arrays.stream(currentKuraServiceConfigs).filter(this::isKuraServicePidString) .collect(Collectors.toMap(this::getKuraServicePid, Function.identity())); } } catch (final IOException | InvalidSyntaxException e) { throw new KuraException(KuraErrorCode.IO_ERROR, e); } return currentConfigs; } private boolean isKuraServicePidString(Configuration config) { return config.getProperties().get(KURA_SERVICE_PID) instanceof String; } private String getKuraServicePid(Configuration config) { return (String) config.getProperties().get(KURA_SERVICE_PID); } private Map getSnapshotConfigs(long id) throws KuraException { XmlComponentConfigurations xmlConfigs = loadEncryptedSnapshotFileContent(id); List configs = xmlConfigs.getConfigurations(); return ComponentUtil.toMap(configs); } private static final class TrackedComponentFactory { private final String factoryPid; private final Bundle provider; public TrackedComponentFactory(final String factoryPid, final Bundle provider) { this.factoryPid = factoryPid; this.provider = provider; } public String getFactoryPid() { return this.factoryPid; } public Bundle getProviderBundle() { return this.provider; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (this.factoryPid == null ? 0 : this.factoryPid.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } TrackedComponentFactory other = (TrackedComponentFactory) obj; if (this.factoryPid == null) { if (other.factoryPid != null) { return false; } } else if (!this.factoryPid.equals(other.factoryPid)) { return false; } return true; } } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/Password.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; /** * * @author matteo.maiero * */ @Deprecated public class Password { private final char[] password; public Password(String password) { super(); this.password = password.toCharArray(); } public Password(char[] password) { super(); this.password = password; } public char[] getPassword() { return this.password; } @Override public String toString() { return new String(this.password); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlComponentConfigurations.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.List; import org.eclipse.kura.configuration.ComponentConfiguration; /** * Utility class to serialize a set of configurations. * This is used to serialize a full snapshot. */ public class XmlComponentConfigurations { private List configurations; public XmlComponentConfigurations() { } public List getConfigurations() { return this.configurations; } public void setConfigurations(List configurations) { this.configurations = configurations; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertiesAdapted.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; /** * Helper class to serialize a property in XML. */ public class XmlConfigPropertiesAdapted { private XmlConfigPropertyAdapted[] properties; public XmlConfigPropertiesAdapted() { } public XmlConfigPropertyAdapted[] getProperties() { return this.properties; } public void setProperties(XmlConfigPropertyAdapted[] properties) { this.properties = properties; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertiesAdapter.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.core.configuration.XmlConfigPropertyAdapted.ConfigPropertyType; import org.eclipse.kura.crypto.CryptoService; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; /** * Helper class to serialize a set of properties in XML. */ public class XmlConfigPropertiesAdapter { public XmlConfigPropertiesAdapted marshal(Map props) throws Exception { List adaptedValues = new ArrayList<>(); if (props != null) { for (Entry prop : props.entrySet()) { XmlConfigPropertyAdapted adaptedValue = new XmlConfigPropertyAdapted(); String key = prop.getKey(); adaptedValue.setName(key); Object value = prop.getValue(); if (value instanceof String) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.STRING_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Long) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.LONG_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Double) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.DOUBLE_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Float) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.FLOAT_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Integer) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.INTEGER_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Byte) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.BYTE_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Character) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.CHAR_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Boolean) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.BOOLEAN_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Short) { adaptedValue.setArray(false); adaptedValue.setType(ConfigPropertyType.SHORT_TYPE); adaptedValue.setValues(new String[] { value.toString() }); } else if (value instanceof Password) { BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); ServiceReference cryptoServiceRef = bundleContext .getServiceReference(CryptoService.class); CryptoService cryptoService = bundleContext.getService(cryptoServiceRef); adaptedValue.setArray(false); adaptedValue.setEncrypted(true); adaptedValue.setType(ConfigPropertyType.PASSWORD_TYPE); adaptedValue.setValues(new String[] { cryptoService.encodeBase64(value.toString()) }); } else if (value instanceof String[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.STRING_TYPE); adaptedValue.setValues((String[]) value); } else if (value instanceof Long[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.LONG_TYPE); Long[] nativeValues = (Long[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Double[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.DOUBLE_TYPE); Double[] nativeValues = (Double[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Float[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.FLOAT_TYPE); Float[] nativeValues = (Float[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Integer[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.INTEGER_TYPE); Integer[] nativeValues = (Integer[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Byte[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.BYTE_TYPE); Byte[] nativeValues = (Byte[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Character[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.CHAR_TYPE); Character[] nativeValues = (Character[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Boolean[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.BOOLEAN_TYPE); Boolean[] nativeValues = (Boolean[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Short[]) { adaptedValue.setArray(true); adaptedValue.setType(ConfigPropertyType.SHORT_TYPE); Short[] nativeValues = (Short[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = nativeValues[i].toString(); } } adaptedValue.setValues(stringValues); } else if (value instanceof Password[]) { BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); ServiceReference cryptoServiceRef = bundleContext .getServiceReference(CryptoService.class); CryptoService cryptoService = bundleContext.getService(cryptoServiceRef); adaptedValue.setArray(true); adaptedValue.setEncrypted(true); adaptedValue.setType(ConfigPropertyType.PASSWORD_TYPE); Password[] nativeValues = (Password[]) value; String[] stringValues = new String[nativeValues.length]; for (int i = 0; i < nativeValues.length; i++) { if (nativeValues[i] != null) { stringValues[i] = cryptoService.encodeBase64(nativeValues[i].toString()); } } adaptedValue.setValues(stringValues); } if (adaptedValue.getValues() == null || adaptedValue.getValues().length > 0) { adaptedValues.add(adaptedValue); } } } XmlConfigPropertiesAdapted result = new XmlConfigPropertiesAdapted(); result.setProperties(adaptedValues.toArray(new XmlConfigPropertyAdapted[] {})); return result; } public Map unmarshal(XmlConfigPropertiesAdapted adaptedPropsAdapted) throws Exception { Map properties = new HashMap<>(); XmlConfigPropertyAdapted[] adaptedProps = adaptedPropsAdapted.getProperties(); if (adaptedProps == null) { return properties; } for (XmlConfigPropertyAdapted adaptedProp : adaptedProps) { String propName = adaptedProp.getName(); ConfigPropertyType type = adaptedProp.getType(); if (type != null) { Object propvalue = null; if (adaptedProp.getArray() == false) { switch (adaptedProp.getType()) { case STRING_TYPE: propvalue = adaptedProp.getValues()[0]; break; case LONG_TYPE: propvalue = Long.parseLong(adaptedProp.getValues()[0]); break; case DOUBLE_TYPE: propvalue = Double.parseDouble(adaptedProp.getValues()[0]); break; case FLOAT_TYPE: propvalue = Float.parseFloat(adaptedProp.getValues()[0]); break; case INTEGER_TYPE: propvalue = Integer.parseInt(adaptedProp.getValues()[0]); break; case BYTE_TYPE: propvalue = Byte.parseByte(adaptedProp.getValues()[0]); break; case CHAR_TYPE: String s = adaptedProp.getValues()[0]; propvalue = Character.valueOf(s.charAt(0)); break; case BOOLEAN_TYPE: propvalue = Boolean.parseBoolean(adaptedProp.getValues()[0]); break; case SHORT_TYPE: propvalue = Short.parseShort(adaptedProp.getValues()[0]); break; case PASSWORD_TYPE: BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); ServiceReference cryptoServiceRef = bundleContext .getServiceReference(CryptoService.class); CryptoService cryptoService = bundleContext.getService(cryptoServiceRef); propvalue = adaptedProp.getValues()[0]; if (adaptedProp.isEncrypted()) { try { propvalue = new Password(cryptoService.decryptAes(((String) propvalue).toCharArray())); } catch (KuraException e) { propvalue = new Password(cryptoService.decodeBase64((String) propvalue)); } } else { propvalue = new Password((String) propvalue); } break; } } else { // If we are dealing with an empty array, skip this element. // Starting from 1.2.0 an empty array will never be present in a snapshot. if (adaptedProp.getValues() == null) { continue; } switch (adaptedProp.getType()) { case STRING_TYPE: propvalue = adaptedProp.getValues(); break; case LONG_TYPE: Long[] longValues = new Long[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { longValues[i] = Long.parseLong(adaptedProp.getValues()[i]); } } propvalue = longValues; break; case DOUBLE_TYPE: Double[] doubleValues = new Double[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { doubleValues[i] = Double.parseDouble(adaptedProp.getValues()[i]); } } propvalue = doubleValues; break; case FLOAT_TYPE: Float[] floatValues = new Float[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { floatValues[i] = Float.parseFloat(adaptedProp.getValues()[i]); } } propvalue = floatValues; break; case INTEGER_TYPE: Integer[] intValues = new Integer[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { intValues[i] = Integer.parseInt(adaptedProp.getValues()[i]); } } propvalue = intValues; break; case BYTE_TYPE: Byte[] byteValues = new Byte[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { byteValues[i] = Byte.parseByte(adaptedProp.getValues()[i]); } } propvalue = byteValues; break; case CHAR_TYPE: Character[] charValues = new Character[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { String s = adaptedProp.getValues()[i]; charValues[i] = Character.valueOf(s.charAt(0)); } } propvalue = charValues; break; case BOOLEAN_TYPE: Boolean[] booleanValues = new Boolean[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { booleanValues[i] = Boolean.parseBoolean(adaptedProp.getValues()[i]); } } propvalue = booleanValues; break; case SHORT_TYPE: Short[] shortValues = new Short[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { shortValues[i] = Short.parseShort(adaptedProp.getValues()[i]); } } propvalue = shortValues; break; case PASSWORD_TYPE: BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); ServiceReference cryptoServiceRef = bundleContext .getServiceReference(CryptoService.class); CryptoService cryptoService = bundleContext.getService(cryptoServiceRef); Password[] pwdValues = new Password[adaptedProp.getValues().length]; for (int i = 0; i < adaptedProp.getValues().length; i++) { if (adaptedProp.getValues()[i] != null) { if (adaptedProp.isEncrypted()) { try { pwdValues[i] = new Password( cryptoService.decryptAes(adaptedProp.getValues()[i].toCharArray())); } catch (KuraException e) { pwdValues[i] = new Password( cryptoService.decodeBase64(adaptedProp.getValues()[i])); } } else { pwdValues[i] = new Password(adaptedProp.getValues()[i]); } } } propvalue = pwdValues; break; } } properties.put(propName, propvalue); } } return properties; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlConfigPropertyAdapted.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; /** * Helper class to serialize a property in XML. */ public class XmlConfigPropertyAdapted { public enum ConfigPropertyType { STRING_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, INTEGER_TYPE, BYTE_TYPE, CHAR_TYPE, BOOLEAN_TYPE, SHORT_TYPE, PASSWORD_TYPE } private String name; private boolean array; private boolean encrypted; private ConfigPropertyType type; private String[] values; public XmlConfigPropertyAdapted() { } public XmlConfigPropertyAdapted(String name, ConfigPropertyType type, String[] values) { super(); this.name = name; this.type = type; this.values = values; this.encrypted = false; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public boolean getArray() { return this.array; } public void setArray(boolean array) { this.array = array; } public ConfigPropertyType getType() { return this.type; } public void setType(ConfigPropertyType type) { this.type = type; } public boolean isEncrypted() { return this.encrypted; } public void setEncrypted(boolean encrypted) { this.encrypted = encrypted; } public String[] getValues() { return this.values; } public void setValues(String[] values) { this.values = values; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/XmlSnapshotIdResult.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration; import java.util.List; /** * Utility class to serialize a set of snapshot ids. */ public class XmlSnapshotIdResult { private List snapshotIds; public XmlSnapshotIdResult() { } public List getSnapshotIds() { return this.snapshotIds; } public void setSnapshotIds(List snapshotIds) { this.snapshotIds = snapshotIds; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/ObjectFactory.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; /** * This object contains factory methods for each * Java content interface and Java element interface * generated in the org.eclipse.kura.core.configuration.metatype package. *

* An ObjectFactory allows you to programmatically * construct new instances of the Java representation * for XML content. The Java representation of XML * content can consist of schema derived interfaces * and classes representing the binding of schema * type definitions, element declarations and model * groups. Factory methods for each of these are * provided in this class. * */ public class ObjectFactory { /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: * org.eclipse.kura.core.configuration.metatype * */ public ObjectFactory() { } /** * Create an instance of {@link Ticon } * */ public Ticon createTicon() { return new Ticon(); } /** * Create an instance of {@link Tattribute } * */ public Tattribute createTattribute() { return new Tattribute(); } /** * Create an instance of {@link Tmetadata } * */ public Tmetadata createTmetadata() { return new Tmetadata(); } /** * Create an instance of {@link Tdesignate } * */ public Tdesignate createTdesignate() { return new Tdesignate(); } /** * Create an instance of {@link Tad } * */ public Tad createTad() { return new Tad(); } /** * Create an instance of {@link Tobject } * */ public Tobject createTobject() { return new Tobject(); } /** * Create an instance of {@link Tocd } * */ public Tocd createTocd() { return new Tocd(); } /** * Create an instance of {@link Toption } * */ public Toption createToption() { return new Toption(); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tad.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.AD; import org.eclipse.kura.configuration.metatype.Option; import org.eclipse.kura.configuration.metatype.Scalar; import org.w3c.dom.Element; /** *

* Java class for Tad complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tad">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Option" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Toption" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="name" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="type" use="required" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tscalar" />
 *       <attribute name="cardinality" type="{http://www.w3.org/2001/XMLSchema}int" default="0" />
 *       <attribute name="min" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="max" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="default" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="required" type="{http://www.w3.org/2001/XMLSchema}boolean" default="true" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tad implements AD { protected List option; protected List any; protected String name; protected String description; protected String id; protected Tscalar type; protected Integer cardinality; protected String min; protected String max; protected String _default; protected Boolean required; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the option property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the option property. * *

* For example, to add a new item, do as follows: * *

     * getOption().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Toption } * * */ @Override @SuppressWarnings("unchecked") public List

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } /** * Gets the value of the name property. * * @return * possible object is * {@link String } * */ @Override public String getName() { return this.name; } /** * Sets the value of the name property. * * @param value * allowed object is * {@link String } * */ public void setName(String value) { this.name = value; } /** * Gets the value of the description property. * * @return * possible object is * {@link String } * */ @Override public String getDescription() { return this.description; } /** * Sets the value of the description property. * * @param value * allowed object is * {@link String } * */ public void setDescription(String value) { this.description = value; } /** * Gets the value of the id property. * * @return * possible object is * {@link String } * */ @Override public String getId() { return this.id; } /** * Sets the value of the id property. * * @param value * allowed object is * {@link String } * */ public void setId(String value) { this.id = value; } /** * Gets the value of the type property. * * @return * possible object is * {@link Tscalar } * */ @Override public Scalar getType() { return Scalar.valueOf(this.type.name()); } /** * Sets the value of the type property. * * @param value * allowed object is * {@link Tscalar } * */ public void setType(Tscalar value) { this.type = value; } /** * Gets the value of the cardinality property. * * @return * possible object is * {@link Integer } * */ @Override public int getCardinality() { if (this.cardinality == null) { return 0; } else { return this.cardinality; } } /** * Sets the value of the cardinality property. * * @param value * allowed object is * {@link Integer } * */ public void setCardinality(Integer value) { this.cardinality = value; } /** * Gets the value of the min property. * * @return * possible object is * {@link String } * */ @Override public String getMin() { return this.min; } /** * Sets the value of the min property. * * @param value * allowed object is * {@link String } * */ public void setMin(String value) { this.min = value; } /** * Gets the value of the max property. * * @return * possible object is * {@link String } * */ @Override public String getMax() { return this.max; } /** * Sets the value of the max property. * * @param value * allowed object is * {@link String } * */ public void setMax(String value) { this.max = value; } /** * Gets the value of the default property. * * @return * possible object is * {@link String } * */ @Override public String getDefault() { return this._default; } /** * Sets the value of the default property. * Commas ',' need to be escaped with '\' if not intended to separate * elements of the array. * * @param value * allowed object is * {@link String }. * If cardinality = n > 1 is specified, then must contain at most n String elements separated by ','. * */ public void setDefault(String value) { this._default = value; } /** * Gets the value of the required property. * * @return * possible object is * {@link Boolean } * */ @Override public boolean isRequired() { if (this.required == null) { return true; } else { return this.required; } } /** * Sets the value of the required property. * * @param value * allowed object is * {@link Boolean } * */ public void setRequired(Boolean value) { this.required = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tattribute.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Attribute; import org.w3c.dom.Element; /** *

* Java class for Tattribute complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tattribute">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Value" type="{http://www.w3.org/2001/XMLSchema}string" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="adref" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="content" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tattribute implements Attribute { protected List value; protected List any; protected String adref; protected String content; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the value property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the value property. * *

* For example, to add a new item, do as follows: * *

     * getValue().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link String } * * */ @Override public List getValue() { if (this.value == null) { this.value = new ArrayList<>(); } return this.value; } /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } /** * Gets the value of the adref property. * * @return * possible object is * {@link String } * */ @Override public String getAdref() { return this.adref; } /** * Sets the value of the adref property. * * @param value * allowed object is * {@link String } * */ public void setAdref(String value) { this.adref = value; } /** * Gets the value of the content property. * * @return * possible object is * {@link String } * */ @Override public String getContent() { return this.content; } /** * Sets the value of the content property. * * @param value * allowed object is * {@link String } * */ public void setContent(String value) { this.content = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tdesignate.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Designate; import org.w3c.dom.Element; /** *

* Java class for Tdesignate complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tdesignate">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Object" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tobject"/>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="pid" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="factoryPid" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="bundle" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="optional" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
 *       <attribute name="merge" type="{http://www.w3.org/2001/XMLSchema}boolean" default="false" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tdesignate implements Designate { protected Tobject object; protected List any; protected String pid; protected String factoryPid; protected String bundle; protected Boolean optional; protected Boolean merge; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the object property. * * @return * possible object is * {@link Tobject } * */ @Override public Tobject getObject() { return this.object; } /** * Sets the value of the object property. * * @param value * allowed object is * {@link Tobject } * */ public void setObject(Tobject value) { this.object = value; } /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } /** * Gets the value of the pid property. * * @return * possible object is * {@link String } * */ @Override public String getPid() { return this.pid; } /** * Sets the value of the pid property. * * @param value * allowed object is * {@link String } * */ public void setPid(String value) { this.pid = value; } /** * Gets the value of the factoryPid property. * * @return * possible object is * {@link String } * */ @Override public String getFactoryPid() { return this.factoryPid; } /** * Sets the value of the factoryPid property. * * @param value * allowed object is * {@link String } * */ public void setFactoryPid(String value) { this.factoryPid = value; } /** * Gets the value of the bundle property. * * @return * possible object is * {@link String } * */ @Override public String getBundle() { return this.bundle; } /** * Sets the value of the bundle property. * * @param value * allowed object is * {@link String } * */ public void setBundle(String value) { this.bundle = value; } /** * Gets the value of the optional property. * * @return * possible object is * {@link Boolean } * */ @Override public boolean isOptional() { if (this.optional == null) { return false; } else { return this.optional; } } /** * Sets the value of the optional property. * * @param value * allowed object is * {@link Boolean } * */ public void setOptional(Boolean value) { this.optional = value; } /** * Gets the value of the merge property. * * @return * possible object is * {@link Boolean } * */ @Override public boolean isMerge() { if (this.merge == null) { return false; } else { return this.merge; } } /** * Sets the value of the merge property. * * @param value * allowed object is * {@link Boolean } * */ public void setMerge(Boolean value) { this.merge = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Ticon.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Icon; import org.w3c.dom.Element; /** *

* Java class for Ticon complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Ticon">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="resource" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="size" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Ticon implements Icon { protected List any; protected String resource; protected BigInteger size; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } public void setAny(Object o) { if (this.any == null) { this.any = new ArrayList<>(); } this.any.add(o); } /** * Gets the value of the resource property. * * @return * possible object is * {@link String } * */ @Override public String getResource() { return this.resource; } /** * Sets the value of the resource property. * * @param value * allowed object is * {@link String } * */ public void setResource(String value) { this.resource = value; } /** * Gets the value of the size property. * * @return * possible object is * {@link BigInteger } * */ @Override public BigInteger getSize() { return this.size; } /** * Sets the value of the size property. * * @param value * allowed object is * {@link BigInteger } * */ public void setSize(BigInteger value) { this.size = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tmetadata.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Designate; import org.eclipse.kura.configuration.metatype.MetaData; import org.eclipse.kura.configuration.metatype.OCD; import org.w3c.dom.Element; /** *

* Java class for Tmetadata complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tmetadata">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="OCD" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tocd" maxOccurs="unbounded" minOccurs="0"/>
 *         <element name="Designate" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tdesignate" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="localization" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tmetadata implements MetaData { protected List ocd; protected List designate; protected List any; protected String localization; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the ocd property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the ocd property. * *

* For example, to add a new item, do as follows: * *

     * getOCD().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Tocd } * * */ @Override public List getOCD() { if (this.ocd == null) { this.ocd = new ArrayList<>(); } return new ArrayList<>(this.ocd); } public void setOCD(Tocd element) { if (this.ocd == null) { this.ocd = new ArrayList<>(); } this.ocd.add(element); } /** * Gets the value of the designate property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the designate property. * *

* For example, to add a new item, do as follows: * *

     * getDesignate().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Tdesignate } * * */ @Override public List getDesignate() { if (this.designate == null) { this.designate = new ArrayList<>(); } return new ArrayList<>(this.designate); } public void setDesignate(Tdesignate td) { if (this.designate == null) { this.designate = new ArrayList<>(); } this.designate.add(td); } /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } public void getAny(Object o) { if (this.any == null) { this.any = new ArrayList<>(); } this.any.add(o); } /** * Gets the value of the localization property. * * @return * possible object is * {@link String } * */ @Override public String getLocalization() { return this.localization; } /** * Sets the value of the localization property. * * @param value * allowed object is * {@link String } * */ public void setLocalization(String value) { this.localization = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tobject.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Attribute; import org.eclipse.kura.configuration.metatype.TObject; import org.w3c.dom.Element; /** *

* Java class for Tobject complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tobject">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Attribute" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tattribute" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="ocdref" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tobject implements TObject { protected List attribute; protected List any; protected String ocdref; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the attribute property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the attribute property. * *

* For example, to add a new item, do as follows: * *

     * getAttribute().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Tattribute } * * */ @Override public List getAttribute() { if (this.attribute == null) { this.attribute = new ArrayList<>(); } return new ArrayList<>(this.attribute); } /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } /** * Gets the value of the ocdref property. * * @return * possible object is * {@link String } * */ @Override public String getOcdref() { return this.ocdref; } /** * Sets the value of the ocdref property. * * @param value * allowed object is * {@link String } * */ public void setOcdref(String value) { this.ocdref = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tocd.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.AD; import org.eclipse.kura.configuration.metatype.Icon; import org.eclipse.kura.configuration.metatype.OCD; import org.w3c.dom.Element; /** *

* Java class for Tocd complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Tocd">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="AD" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Tad" maxOccurs="unbounded"/>
 *         <element name="Icon" type="{http://www.osgi.org/xmlns/metatype/v1.2.0}Ticon" maxOccurs="unbounded" minOccurs="0"/>
 *         <any processContents='lax' namespace='##other' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="description" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Tocd implements OCD { protected List ad; protected List icon; protected List any; protected String name; protected String description; protected String id; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the ad property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the ad property. * *

* For example, to add a new item, do as follows: * *

     * getAD().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Tad } * * */ @Override public List getAD() { if (this.ad == null) { this.ad = new ArrayList<>(); } return new ArrayList<>(this.ad); } public void addAD(Tad tad) { if (this.ad == null) { this.ad = new ArrayList<>(); } this.ad.add(tad); } /** * Gets the value of the icon property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the icon property. * *

* For example, to add a new item, do as follows: * *

     * getIcon().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Ticon } * * */ @Override public List getIcon() { if (this.icon == null) { this.icon = new ArrayList<>(); } return new ArrayList<>(this.icon); } public void setIcon(Ticon ti) { if (this.icon == null) { this.icon = new ArrayList<>(); } this.icon.add(ti); } /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } public void setAny(Object o) { if (this.any == null) { this.any = new ArrayList<>(); } this.any.add(o); } /** * Gets the value of the name property. * * @return * possible object is * {@link String } * */ @Override public String getName() { return this.name; } /** * Sets the value of the name property. * * @param value * allowed object is * {@link String } * */ public void setName(String value) { this.name = value; } /** * Gets the value of the description property. * * @return * possible object is * {@link String } * */ @Override public String getDescription() { return this.description; } /** * Sets the value of the description property. * * @param value * allowed object is * {@link String } * */ public void setDescription(String value) { this.description = value; } /** * Gets the value of the id property. * * @return * possible object is * {@link String } * */ @Override public String getId() { return this.id; } /** * Sets the value of the id property. * * @param value * allowed object is * {@link String } * */ public void setId(String value) { this.id = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Toption.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.kura.configuration.metatype.Option; import org.w3c.dom.Element; /** *

* Java class for Toption complex type. * *

* The following schema fragment specifies the expected content contained within this class. * *

 * <complexType name="Toption">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <any processContents='lax' maxOccurs="unbounded" minOccurs="0"/>
 *       </sequence>
 *       <attribute name="label" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <attribute name="value" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
 *       <anyAttribute/>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * 
* * */ public class Toption implements Option { protected List any; protected String label; protected String value; private final Map otherAttributes = new HashMap<>(); /** * Gets the value of the any property. * *

* This accessor method returns a reference to the live list, * not a snapshot. Therefore any modification you make to the * returned list will be present inside the JAXB object. * This is why there is not a set method for the any property. * *

* For example, to add a new item, do as follows: * *

     * getAny().add(newItem);
     * 
* * *

* Objects of the following type(s) are allowed in the list * {@link Element } * {@link Object } * * */ public List getAny() { if (this.any == null) { this.any = new ArrayList<>(); } return this.any; } public void setAny(Object o) { if (this.any == null) { this.any = new ArrayList<>(); } this.any.add(o); } /** * Gets the value of the label property. * * @return * possible object is * {@link String } * */ @Override public String getLabel() { return this.label; } /** * Sets the value of the label property. * * @param value * allowed object is * {@link String } * */ public void setLabel(String value) { this.label = value; } /** * Gets the value of the value property. * * @return * possible object is * {@link String } * */ @Override public String getValue() { return this.value; } /** * Sets the value of the value property. * * @param value * allowed object is * {@link String } * */ public void setValue(String value) { this.value = value; } /** * Gets a map that contains attributes that aren't bound to any typed property on this class. * *

* the map is keyed by the name of the attribute and * the value is the string value of the attribute. * * the map returned by this method is live, and you can add new attribute * by updating the map directly. Because of this design, there's no setter. * * * @return * always non-null */ public Map getOtherAttributes() { return this.otherAttributes; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/Tscalar.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; /** *

* Java class for Tscalar. * *

* The following schema fragment specifies the expected content contained within this class. *

* *

 * <simpleType name="Tscalar">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="String"/>
 *     <enumeration value="Long"/>
 *     <enumeration value="Double"/>
 *     <enumeration value="Float"/>
 *     <enumeration value="Integer"/>
 *     <enumeration value="Byte"/>
 *     <enumeration value="Char"/>
 *     <enumeration value="Boolean"/>
 *     <enumeration value="Short"/>
 *     <enumeration value="Password"/>
 *   </restriction>
 * </simpleType>
 * 
* */ public enum Tscalar { STRING("String"), LONG("Long"), DOUBLE("Double"), FLOAT("Float"), INTEGER("Integer"), BYTE("Byte"), CHAR("Char"), BOOLEAN("Boolean"), SHORT("Short"), PASSWORD("Password"); private final String value; Tscalar(String v) { this.value = v; } public String value() { return this.value; } public static Tscalar fromValue(String v) { for (Tscalar c : Tscalar.values()) { if (c.value.equals(v)) { return c; } } throw new IllegalArgumentException(v); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/metatype/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, // vhudson-jaxb-ri-2.2-147 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.11.25 at 06:05:15 PM CET // package org.eclipse.kura.core.configuration.metatype; ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/package-info.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in // JDK 6 // See http://java.sun.com/xml/jaxb // Any modifications to this file will be lost upon recompilation of the source schema. // Generated on: 2012.10.26 at 02:11:54 PM CEST // package org.eclipse.kura.core.configuration; ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/upgrade/ConfigurationUpgrade.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.configuration.upgrade; import java.util.Map; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.BundleContext; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.component.ComponentConstants; public class ConfigurationUpgrade { private static final String KURA_CLOUD_SERVICE_FACTORY_PID = "kura.cloud.service.factory.pid"; private static final String FACTORY_PID = "org.eclipse.kura.core.cloud.factory.DefaultCloudServiceFactory"; private static final String CLOUD_SERVICE_FACTORY_PID = "org.eclipse.kura.cloud.CloudService"; private static final String DATA_SERVICE_FACTORY_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_FACTORY_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String CLOUD_SERVICE_PID = "org.eclipse.kura.cloud.CloudService"; private static final String DATA_SERVICE_PID = "org.eclipse.kura.data.DataService"; private static final String DATA_TRANSPORT_SERVICE_PID = "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport"; private static final String DATA_SERVICE_REFERENCE_NAME = "DataService"; private static final String DATA_TRANSPORT_SERVICE_REFERENCE_NAME = "DataTransportService"; private static final String REFERENCE_TARGET_VALUE_FORMAT = "(" + ConfigurationService.KURA_SERVICE_PID + "=%s)"; public static void upgrade(final ComponentConfiguration config, final BundleContext bundleContext) { if (config == null) { return; } String pid = config.getPid(); final Map props = config.getConfigurationProperties(); if (props == null) { return; } final Object factoryPid = props.get(ConfigurationAdmin.SERVICE_FACTORYPID); if (CLOUD_SERVICE_PID.equals(pid)) { props.put(ConfigurationAdmin.SERVICE_FACTORYPID, CLOUD_SERVICE_FACTORY_PID); String name = DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; props.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, DATA_SERVICE_PID)); props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID); } else if (DATA_SERVICE_PID.equals(pid)) { props.put(ConfigurationAdmin.SERVICE_FACTORYPID, DATA_SERVICE_FACTORY_PID); String name = DATA_TRANSPORT_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX; props.put(name, String.format(REFERENCE_TARGET_VALUE_FORMAT, DATA_TRANSPORT_SERVICE_PID)); props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID); } else if (DATA_TRANSPORT_SERVICE_PID.equals(pid)) { props.put(ConfigurationAdmin.SERVICE_FACTORYPID, DATA_TRANSPORT_SERVICE_FACTORY_PID); props.put(KURA_CLOUD_SERVICE_FACTORY_PID, FACTORY_PID); } else if (WireAssetConfigurationUpgrade.WIRE_ASSET_FACTORY_PID.equals(factoryPid)) { WireAssetConfigurationUpgrade.upgrade(props); } } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/upgrade/WireAssetConfigurationUpgrade.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration.upgrade; import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public final class WireAssetConfigurationUpgrade { static final String WIRE_ASSET_FACTORY_PID = "org.eclipse.kura.wire.WireAsset"; private static final String CHANNEL_PROPERTY_SEPARATOR = "#"; private static final String CHANNEL_NAME_PROPERTY_SUFFIX = CHANNEL_PROPERTY_SEPARATOR + "+name"; private static final String EMIT_ALL_CHANNELS_PROP_NAME = "emit.all.channels"; private WireAssetConfigurationUpgrade() { } static void upgrade(final Map properties) { if (properties.containsKey(EMIT_ALL_CHANNELS_PROP_NAME)) { return; } properties.put(EMIT_ALL_CHANNELS_PROP_NAME, false); final Set channelNames = getChannelNames(properties); for (final String channelName : channelNames) { properties.put(channelName + CHANNEL_NAME_PROPERTY_SUFFIX, channelName); } } static Set getChannelNames(final Map properties) { final Set channelNames = new HashSet<>(); for (final Entry e : properties.entrySet()) { final String key = e.getKey(); final int index = key.indexOf(CHANNEL_PROPERTY_SEPARATOR); if (index == -1) { continue; } final String channelName = key.substring(0, index); channelNames.add(channelName); } return channelNames; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/CollectionsUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration.util; import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Objects; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.configuration.metatype.AD; import org.eclipse.kura.configuration.metatype.OCD; import org.eclipse.kura.configuration.metatype.Scalar; public class CollectionsUtil { public static Map dictionaryToMap(Dictionary dictionary, OCD ocd) { if (dictionary == null) { return null; } Map ads = new HashMap<>(); if (ocd != null) { for (AD ad : ocd.getAD()) { ads.put(ad.getId(), ad); } } Map map = new HashMap<>(); Enumeration keys = dictionary.keys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); Object value = dictionary.get(key); AD ad = ads.get(key); if (ad != null && ad.getType() != null && Scalar.PASSWORD.equals(ad.getType())) { if (value instanceof char[]) { map.put(key, new Password((char[]) value)); } else if (value instanceof String[]) { map.put(key, convertStringsToPasswords((String[]) value)); } else { map.put(key, new Password(value.toString())); } } else { map.put(key, value); } } return map; } private static Password[] convertStringsToPasswords(String[] value) { Password[] result = new Password[value.length]; for (int i = 0; i < value.length; i++) { result[i] = new Password(value[i]); } return result; } public static Dictionary mapToDictionary(Map map) { if (map == null) { return null; } Dictionary dictionary = new Hashtable<>(); Iterator keys = map.keySet().iterator(); while (keys.hasNext()) { String key = keys.next(); Object value = map.get(key); if (value != null) { // TODO: this should be removed in next version. Password values // should be kept as they are and not mapped to String objects. This // was originally done due to Password class not in APIs, but this is // not the condition anymore. This change would cause third party code // to receive Password objects instead of strings. At the other side, // managing everything with Password objects would make everything // more logic and consistent. if (value instanceof Password) { dictionary.put(key, value.toString()); } else if (value instanceof Password[]) { Password[] passwordArray = (Password[]) value; String[] passwords = new String[passwordArray.length]; for (int i = 0; i < passwordArray.length; i++) { passwords[i] = passwordArray[i].toString(); } dictionary.put(key, passwords); } else { dictionary.put(key, value); } } } return dictionary; } public static boolean equals(final Dictionary first, final Dictionary second) { if (first == null || second == null) { return first == second; } if (first.size() != second.size()) { return false; } final Enumeration keys = first.keys(); while (keys.hasMoreElements()) { final String key = keys.nextElement(); if (!Objects.deepEquals(first.get(key), second.get(key))) { return false; } } return true; } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/ComponentUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.configuration.util; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLStreamException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.configuration.metatype.AD; import org.eclipse.kura.configuration.metatype.Designate; import org.eclipse.kura.configuration.metatype.MetaData; import org.eclipse.kura.configuration.metatype.OCD; import org.eclipse.kura.configuration.metatype.Scalar; import org.eclipse.kura.core.configuration.metatype.Tmetadata; import org.eclipse.kura.core.configuration.metatype.Tocd; import org.eclipse.kura.core.util.IOUtil; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.service.metatype.MetaTypeInformation; import org.osgi.service.metatype.MetaTypeService; import org.osgi.service.metatype.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility class to handle the loading of the meta-information * of a bundle or one of its Services/Components. */ public class ComponentUtil { private static final Logger logger = LoggerFactory.getLogger(ComponentUtil.class); private static final String OSGI_INF_METATYPE = "OSGI-INF/metatype/"; private ComponentUtil() { // Do nothing... } /** * Returns a Map with all the MetaType Object Class Definitions contained in the bundle. * * @param ctx * @param bnd * @return */ public static Map getMetadata(BundleContext ctx, Bundle bnd) { final Map bundleMetadata = new HashMap<>(); final ServiceReference ref = ctx.getServiceReference(MetaTypeService.class); final MetaTypeService metaTypeService = ctx.getService(ref); try { final MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(bnd); if (mti != null) { final List pids = new ArrayList<>(); pids.addAll(Arrays.asList(mti.getPids())); pids.addAll(Arrays.asList(mti.getFactoryPids())); for (String pid : pids) { final Tmetadata metadata; try { metadata = readMetadata(bnd, pid); if (metadata != null) { bundleMetadata.put(pid, metadata); } } catch (Exception e) { // ignore: Metadata for the specified pid is not found logger.warn("Error loading Metadata for pid " + pid, e); } } } } finally { ctx.ungetService(ref); } return bundleMetadata; } /** * Returns the Designate for the given pid */ public static Designate getDesignate(final Tmetadata metadata, final String pid) { if (metadata == null || pid == null) { return null; } final List designates = metadata.getDesignate(); if (designates == null) { return null; } for (final Designate designate : designates) { if (pid.equals(designate.getPid())) { return designate; } if (pid.equals(designate.getFactoryPid())) { return designate; } } return null; } /** * Returns the Designate for the given pid */ public static OCD getOCD(Tmetadata metadata, String pid) { if (metadata.getOCD() != null && !metadata.getOCD().isEmpty()) { for (OCD ocd : metadata.getOCD()) { if (ocd.getId() != null && ocd.getId().equals(pid)) { return ocd; } } } return null; } /** * Returns a Map with all the MetaType Object Class Definitions contained in the bundle. * * @param ctx * @param bnd * @return */ public static Map getObjectClassDefinition(BundleContext ctx, Bundle bnd) { Map bundleDefaults = new HashMap<>(); ServiceReference ref = ctx.getServiceReference(MetaTypeService.class); MetaTypeService metaTypeService = ctx.getService(ref); MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(bnd); if (mti != null) { String[] pids = mti.getPids(); if (pids != null) { for (String pid : pids) { OCD ocd = null; try { ocd = readObjectClassDefinition(bnd, pid); if (ocd != null) { bundleDefaults.put(pid, ocd); } } catch (Exception e) { // ignore: OCD for the specified pid is not found logger.warn("Error loading OCD for pid " + pid, e); } } } } return bundleDefaults; } /** * Returns the ObjectClassDefinition for the provided Service pid * as returned by the native OSGi MetaTypeService. * The returned ObjectClassDefinition is a thick object tied to * OSGi framework which masks certain attributes of the OCD XML * file - like required and min/max values - but which exposes * business logic like the validate method for each attribute. * * @param ctx * @param pid * @return */ public static ObjectClassDefinition getObjectClassDefinition(BundleContext ctx, String pid) { // ServiceReference ref = ctx.getServiceReference(MetaTypeService.class); MetaTypeService metaTypeService = ctx.getService(ref); MetaTypeInformation mti = metaTypeService.getMetaTypeInformation(ctx.getBundle()); ObjectClassDefinition ocd = null; try { if (mti != null) { ocd = mti.getObjectClassDefinition(pid, null); // default locale } } catch (IllegalArgumentException iae) { // ignore: OCD for the specified pid is not found } return ocd; } /** * Returned the Tmetadata as parsed from the XML file. * The returned Tmetadata is just an object representation of the Metadata * element contained in the XML MetaData file and it does not * contain any extra post-processing of the loaded information. * * @param ctx * @param pid * ID of the service whose OCD should be loaded * @return * @throws IOException * @throws XMLStreamException * @throws FactoryConfigurationError */ public static Tmetadata readMetadata(Bundle bundle, String pid) throws IOException, KuraException, FactoryConfigurationError { Tmetadata metaData = null; StringBuilder sbMetatypeXmlName = new StringBuilder(); sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(".xml"); String metatypeXmlName = sbMetatypeXmlName.toString(); String metatypeXml = IOUtil.readResource(bundle, metatypeXmlName); if (metatypeXml != null) { metaData = unmarshal(metatypeXml, Tmetadata.class); } return metaData; } /** * Returned the ObjectClassDefinition as parsed from the XML file. * The returned OCD is just an object representation of the OCD * element contained in the XML MetaData file and it does not * contain any extra post-processing of the loaded information. * * @param resourceUrl * Url of the MetaData XML file which needs to be loaded * @return * @throws IOException * @throws XMLStreamException * @throws FactoryConfigurationError */ public static OCD readObjectClassDefinition(URL resourceUrl) throws IOException, FactoryConfigurationError, KuraException { OCD ocd = null; String metatypeXml = IOUtil.readResource(resourceUrl); if (metatypeXml != null) { MetaData metaData = unmarshal(metatypeXml, MetaData.class); if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) { ocd = metaData.getOCD().get(0); } else { logger.warn("Cannot find OCD for component with url: {}", resourceUrl); } } return ocd; } /** * Returned the ObjectClassDefinition as parsed from the XML file. * The returned OCD is just an object representation of the OCD * element contained in the XML MetaData file and it does not * contain any extra post-processing of the loaded information. * * @param pid * ID of the service whose OCD should be loaded * @return * @throws IOException * @throws XMLStreamException * @throws FactoryConfigurationError */ public static Tocd readObjectClassDefinition(String pid) throws IOException, KuraException, FactoryConfigurationError { Tocd ocd = null; StringBuilder sbMetatypeXmlName = new StringBuilder(); sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(".xml"); String metatypeXmlName = sbMetatypeXmlName.toString(); String metatypeXml = IOUtil.readResource(metatypeXmlName); if (metatypeXml != null) { Tmetadata metaData = unmarshal(metatypeXml, Tmetadata.class); if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) { ocd = (Tocd) metaData.getOCD().get(0); } else { logger.warn("Cannot find OCD for component with pid: {}", pid); } } return ocd; } /** * Returned the ObjectClassDefinition as parsed from the XML file. * The returned OCD is just an object representation of the OCD * element contained in the XML MetaData file and it does not * contain any extra post-processing of the loaded information. * * @param ctx * @param pid * ID of the service whose OCD should be loaded * @return * @throws IOException * @throws XMLStreamException * @throws FactoryConfigurationError */ public static Tocd readObjectClassDefinition(Bundle bundle, String pid) throws IOException, KuraException, FactoryConfigurationError { Tocd ocd = null; StringBuilder sbMetatypeXmlName = new StringBuilder(); sbMetatypeXmlName.append(OSGI_INF_METATYPE).append(pid).append(".xml"); String metatypeXmlName = sbMetatypeXmlName.toString(); String metatypeXml = IOUtil.readResource(bundle, metatypeXmlName); if (metatypeXml != null) { Tmetadata metaData = unmarshal(metatypeXml, Tmetadata.class); if (metaData.getOCD() != null && !metaData.getOCD().isEmpty()) { ocd = (Tocd) metaData.getOCD().get(0); } } return ocd; } public static Map getDefaultProperties(OCD ocd, ComponentContext ctx) { // // reconcile by looping through the ocd properties Map defaults = null; defaults = new HashMap<>(); if (ocd != null) { List attrDefs = ocd.getAD(); if (attrDefs != null) { for (AD attrDef : attrDefs) { String id = attrDef.getId(); Object defaultValue = getDefaultValue(attrDef, ctx); if (defaults.get(id) == null && defaultValue != null) { defaults.put(id, defaultValue); } } } } return defaults; } private static Object getDefaultValue(AD attrDef, ComponentContext ctx) { // get the default value string from the AD // then split it by comma-separate list // keeping in mind the possible escape sequence "\," String defaultValue = attrDef.getDefault(); if (defaultValue == null || defaultValue.isEmpty()) { return null; } Object[] objectValues = null; Scalar type = attrDef.getType(); if (type != null) { String[] defaultValues = StringUtil.splitValues(defaultValue); // convert string values into object values int cardinality = attrDef.getCardinality(); objectValues = getObjectValue(type, defaultValues, ctx); if (objectValues != null && (cardinality == 0 || cardinality == 1 || cardinality == -1)) { // return one single object // if cardinality is 0 or abs(1) return objectValues[0]; } } else { logger.warn("Unknown type for attribute {}", attrDef.getId()); } return objectValues; } private static Object[] getObjectValue(Scalar type, String[] defaultValues, ComponentContext ctx) { List values = new ArrayList<>(); switch (type) { case BOOLEAN: for (String value : defaultValues) { values.add(Boolean.valueOf(value)); } return values.toArray(new Boolean[] {}); case BYTE: for (String value : defaultValues) { values.add(Byte.valueOf(value)); } return values.toArray(new Byte[] {}); case CHAR: for (String value : defaultValues) { values.add(Character.valueOf(value.charAt(0))); } return values.toArray(new Character[] {}); case DOUBLE: for (String value : defaultValues) { values.add(Double.valueOf(value)); } return values.toArray(new Double[] {}); case FLOAT: for (String value : defaultValues) { values.add(Float.valueOf(value)); } return values.toArray(new Float[] {}); case INTEGER: for (String value : defaultValues) { values.add(Integer.valueOf(value)); } return values.toArray(new Integer[] {}); case LONG: for (String value : defaultValues) { values.add(Long.valueOf(value)); } return values.toArray(new Long[] {}); case SHORT: for (String value : defaultValues) { values.add(Short.valueOf(value)); } return values.toArray(new Short[] {}); case PASSWORD: ServiceReference sr = ctx.getBundleContext().getServiceReference(CryptoService.class); CryptoService cryptoService = ctx.getBundleContext().getService(sr); for (String value : defaultValues) { try { values.add(new Password(cryptoService.encryptAes(value.toCharArray()))); } catch (Exception e) { values.add(new Password(value)); } } return values.toArray(new Password[] {}); case STRING: return defaultValues; } return null; } private static ServiceReference[] getXmlUnmarshallers() { String filterString = String.format("(&(kura.service.pid=%s))", "org.eclipse.kura.xml.marshaller.unmarshaller.provider"); return ServiceUtil.getServiceReferences(FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext(), Unmarshaller.class, filterString); } private static void ungetServiceReferences(final ServiceReference[] refs) { ServiceUtil.ungetServiceReferences(FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext(), refs); } protected static T unmarshal(String string, Class clazz) throws KuraException { T result = null; ServiceReference[] unmarshallerSRs = getXmlUnmarshallers(); try { for (final ServiceReference unmarshallerSR : unmarshallerSRs) { Unmarshaller unmarshaller = FrameworkUtil.getBundle(ComponentUtil.class).getBundleContext() .getService(unmarshallerSR); result = unmarshaller.unmarshal(string, clazz); } } catch (Exception e) { logger.warn("Failed to extract persisted configuration."); } finally { ungetServiceReferences(unmarshallerSRs); } if (result == null) { throw new KuraException(KuraErrorCode.DECODER_ERROR, "value"); } return result; } /* * Encrypt a list of {@link org.eclipse.kura.ComponentConfiguration}s using the given CryptoService */ public static void encryptConfigs(List configs, final CryptoService cryptoService) { if (configs != null) { for (ComponentConfiguration config : configs) { encryptConfigurationProperties(config.getConfigurationProperties(), cryptoService); } } } /* * Encrypt a map of properties using the given CryptoService */ public static void encryptConfigurationProperties(Map propertiesToUpdate, final CryptoService cryptoService) { encryptConfigurationProperties(propertiesToUpdate, cryptoService, false); } public static Map encryptConfigurationProperties(final Map original, final CryptoService cryptoService, final boolean clone) { if (original == null) { return null; } Optional> result = Optional.empty(); if (!clone) { result = Optional.of(original); } for (Entry property : original.entrySet()) { Object configValue = property.getValue(); if (configValue instanceof Password || configValue instanceof Password[]) { final Map resultProperties; if (result.isPresent()) { resultProperties = result.get(); } else { resultProperties = new HashMap<>(original); result = Optional.of(resultProperties); } try { Object encryptedValue = encryptPasswordProperties(configValue, cryptoService); resultProperties.put(property.getKey(), encryptedValue); } catch (KuraException e) { logger.warn("Failed to encrypt Password property: {}", property.getKey()); resultProperties.remove(property.getKey()); } } } return result.orElse(original); } private static Object encryptPasswordProperties(Object configValue, final CryptoService cryptoService) throws KuraException { Object encryptedValue = null; if (configValue instanceof Password) { encryptedValue = encryptPassword((Password) configValue, cryptoService); } else if (configValue instanceof Password[]) { Password[] passwordArray = (Password[]) configValue; Password[] encryptedPasswords = new Password[passwordArray.length]; for (int i = 0; i < passwordArray.length; i++) { encryptedPasswords[i] = encryptPassword(passwordArray[i], cryptoService); } encryptedValue = encryptedPasswords; } return encryptedValue; } private static boolean isEncrypted(Password configPassword, final CryptoService cryptoService) { boolean result = false; try { cryptoService.decryptAes(configPassword.getPassword()); result = true; } catch (Exception e) { // Do nothing... } return result; } private static Password encryptPassword(Password password, final CryptoService cryptoService) throws KuraException { if (!isEncrypted(password, cryptoService)) { return new Password(cryptoService.encryptAes(password.getPassword())); } return password; } /* * Converts a list of {@link org.eclipse.kura.core.configuration.ComponentConfiguration}s to a map whose keys are * the component pids. */ public static Map toMap(final List configs) { return configs.stream().collect(Collectors.toMap(ComponentConfiguration::getPid, Function.identity())); } } ================================================ FILE: kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/util/StringUtil.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.configuration.util; import java.util.ArrayList; import java.util.List; import org.eclipse.kura.configuration.Password; public class StringUtil { private static final char DELIMITER = ','; private static final char ESCAPE = '\\'; private StringUtil() { // Do nothing... } public static String[] splitValues(String strValues) { if (strValues == null) { return null; } // The trick is to strip out unescaped whitespace characters before and // after the input string as well as before and after each // individual token within the input string without losing any escaped // whitespace characters. Whitespace between two non-whitespace // characters may or may not be escaped. Also, any character may be // escaped. The escape character is '\'. The delimiter is ','. List values = new ArrayList<>(); StringBuilder buffer = new StringBuilder(); // Loop over the characters within the input string and extract each // value token. for (int i = 0; i < strValues.length(); i++) { char c1 = strValues.charAt(i); switch (c1) { case DELIMITER: // When the delimiter is encountered, add the extracted // token to the result and prepare the buffer to receive the // next token. values.add(buffer.toString()); buffer.delete(0, buffer.length()); break; case ESCAPE: // When the escape is encountered, add the immediately // following character to the token, unless the end of the // input has been reached. Note this will result in loop // counter 'i' being incremented twice, once here and once // at the end of the loop. if (i + 1 < strValues.length()) { buffer.append(strValues.charAt(++i)); } // If the ESCAPE character occurs as the last character // of the string, ignore it. break; default: // For all other characters, add them to the current token // unless dealing with unescaped whitespace at the beginning // or end. We know the whitespace is unescaped because it // would have been handled in the ESCAPE case otherwise. if (Character.isWhitespace(c1)) { // Ignore unescaped whitespace at the beginning of the // token. if (buffer.length() == 0) { continue; } // If the whitespace is not at the beginning, look // forward, starting with the next character, to see if // it's in the middle or at the end. Unescaped // whitespace in the middle is okay. for (int j = i + 1; j < strValues.length(); j++) { // Keep looping until the end of the string is // reached or a non-whitespace character other than // the escape is seen. char c2 = strValues.charAt(j); if (!Character.isWhitespace(c2)) { // If the current character is not the DELIMITER, all whitespace // characters are significant and should be added to the token. // Otherwise, they're at the end and should be ignored. But watch // out for an escape character at the end of the input. Ignore it // and any previous insignificant whitespace if it exists. if (c2 == ESCAPE && j + 1 >= strValues.length()) { continue; } if (c2 != DELIMITER) { buffer.append(strValues.substring(i, j)); } // Let loop counter i catch up with the inner loop but keep in // mind it will still be incremented at the end of the outer loop. i = j - 1; break; } } } else { // For non-whitespace characters. buffer.append(c1); } } } // Don't forget to add the last token. values.add(buffer.toString()); return values.toArray(new String[] {}); } public static String valueToString(Object value) { String result = null; if (value == null) { result = null; } else if (value instanceof String) { result = value.toString(); } else if (value instanceof Long) { result = value.toString(); } else if (value instanceof Double) { result = value.toString(); } else if (value instanceof Float) { result = value.toString(); } else if (value instanceof Integer) { result = value.toString(); } else if (value instanceof Byte) { result = value.toString(); } else if (value instanceof Character) { result = value.toString(); } else if (value instanceof Boolean) { result = value.toString(); } else if (value instanceof Short) { result = value.toString(); } else if (value instanceof Password) { result = value.toString(); } else if (value instanceof String[]) { StringBuilder sb = new StringBuilder(); String[] ss = (String[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Long[]) { StringBuilder sb = new StringBuilder(); Long[] ss = (Long[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Double[]) { StringBuilder sb = new StringBuilder(); Double[] ss = (Double[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Float[]) { StringBuilder sb = new StringBuilder(); Float[] ss = (Float[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Integer[]) { StringBuilder sb = new StringBuilder(); Integer[] ss = (Integer[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Byte[]) { StringBuilder sb = new StringBuilder(); Byte[] ss = (Byte[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Character[]) { StringBuilder sb = new StringBuilder(); Character[] ss = (Character[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Boolean[]) { StringBuilder sb = new StringBuilder(); Boolean[] ss = (Boolean[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Short[]) { StringBuilder sb = new StringBuilder(); Short[] ss = (Short[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } else if (value instanceof Password[]) { StringBuilder sb = new StringBuilder(); String[] ss = (String[]) value; for (int i = 0; i < ss.length; i++) { if (ss[i] != null) { sb.append(escapeString(ss[i].toString())); if (i != ss.length - 1) { sb.append(","); } } } result = sb.toString(); } return result; } public static String escapeString(String s) { String escaped = s; escaped = escaped.replace("\\", "\\\\"); escaped = escaped.replace(",", "\\,"); escaped = escaped.replace(" ", "\\ "); return escaped; } public static String unescapeString(String s) { String value = s; // remove all space at the beginning of the string which are not escaped value = value.replaceAll("^((? ================================================ FILE: kura/org.eclipse.kura.core.crypto/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.crypto/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.crypto/build.properties ================================================ # # Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about_files/,\ about.html src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.crypto/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.crypto 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.crypto.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.core.crypto/src/main/java/org/eclipse/kura/core/crypto/CryptoServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.crypto; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingException; import java.nio.charset.CharsetDecoder; import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; import java.util.Base64; import java.util.Optional; import java.util.Properties; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.system.SystemService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CryptoServiceImpl implements CryptoService { private static final Logger logger = LoggerFactory.getLogger(CryptoServiceImpl.class); private static final String PARAMETER_EXCEPTION_CAUSE = "parameter"; private static final String DECRYPT_EXCEPTION_CAUSE = "decrypt"; private static final String VALUE_EXCEPTION_CAUSE = "value"; private static final String ALGORITHM = "AES"; private static final String CIPHER = "AES/GCM/NoPadding"; private static final int AUTH_TAG_LENGTH_BIT = 128; private static final int IV_SIZE = 12; private static final String ENCRYPTED_STRING_SEPARATOR = "-"; private static final byte[] DEFAULT_SECRET_KEY = "rv;ipse329183!@#".getBytes(StandardCharsets.UTF_8); private static final String SECRET_KEY_CREDENTIAL_ID = "kura_encryption_key"; private static final String SECRET_KEY_SYSTEM_PROPERTY_NAME = "org.eclipse.kura.core.crypto.secretKey"; private String keystorePasswordPath; private final SecureRandom random = new SecureRandom(); private SystemService systemService; private Optional secretKey; public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { this.systemService = null; } protected void activate() { this.secretKey = loadCustomEncryptionKey().filter(CryptoServiceImpl::isEncryptionKeyValid); this.keystorePasswordPath = this.systemService.getKuraDataDirectory() + File.separator + "store.save"; } private Optional loadCustomEncryptionKey() { try { final Optional loader = SystemdCredentialLoader.fromEnv(); if (loader.isPresent()) { final Optional keyFromSystemd = loader.get().loadCredential(SECRET_KEY_CREDENTIAL_ID); if (keyFromSystemd.isPresent()) { logger.debug("using key from systemd"); return Optional.of(keyFromSystemd.get()); } } } catch (final Exception e) { logger.warn("Unexpected exception loading encryption provided by systemd", e); } return Optional.ofNullable(System.getProperty(SECRET_KEY_SYSTEM_PROPERTY_NAME)).filter(k -> !k.isEmpty()) .map(k -> { logger.debug("using key from system properties"); return k.getBytes(StandardCharsets.UTF_8); }); } private static boolean isEncryptionKeyValid(final byte[] key) { return (key.length == 16 || key.length == 24 || key.length == 32) && !Arrays.equals(key, DEFAULT_SECRET_KEY); } @Override public char[] encryptAes(char[] value) throws KuraException { try { Key key = generateKey(); Cipher c = Cipher.getInstance(CIPHER); byte[] iv = new byte[IV_SIZE]; this.random.nextBytes(iv); c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv)); byte[] encryptedBytes = c.doFinal(charArrayToByteArray(value)); String ivString = base64Encode(iv); String encryptedMessage = base64Encode(encryptedBytes); return (ivString + ENCRYPTED_STRING_SEPARATOR + encryptedMessage).toCharArray(); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "encrypt"); } catch (InvalidKeyException | IllegalBlockSizeException | BadPaddingException | CharacterCodingException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_EXCEPTION_CAUSE); } catch (InvalidAlgorithmParameterException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE); } } @Override public OutputStream aesEncryptingStream(OutputStream stream) throws KuraException { try { Key key = generateKey(); Cipher c = Cipher.getInstance(CIPHER); byte[] iv = new byte[IV_SIZE]; this.random.nextBytes(iv); c.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv)); stream.write(base64Encode(iv).getBytes(StandardCharsets.UTF_8)); stream.write(ENCRYPTED_STRING_SEPARATOR.getBytes(StandardCharsets.UTF_8)); final OutputStream base64Encoder = Base64.getEncoder().wrap(stream); return new CipherOutputStream(base64Encoder, c); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "encrypt"); } catch (IOException e) { throw new KuraException(KuraErrorCode.IO_ERROR, e); } catch (InvalidAlgorithmParameterException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE); } catch (InvalidKeyException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, VALUE_EXCEPTION_CAUSE); } } private byte[] charArrayToByteArray(char[] value) throws CharacterCodingException { ByteBuffer byteBuffer; try { byteBuffer = getUtf8Encoder().encode(CharBuffer.wrap(value)); } catch (CharacterCodingException e) { // fallback for backward compatibility byteBuffer = ByteBuffer.wrap(new String(value).getBytes()); } byte[] encodedBytes = new byte[byteBuffer.limit()]; byteBuffer.get(encodedBytes); return encodedBytes; } private char[] byteArrayToCharArray(byte[] value) throws CharacterCodingException { CharBuffer charBuffer; try { charBuffer = getUtf8Decoder().decode(ByteBuffer.wrap(value)); } catch (CharacterCodingException e) { // fallback for backward compatibility charBuffer = CharBuffer.wrap(new String(value).toCharArray()); } char[] decodedChar = new char[charBuffer.limit()]; charBuffer.get(decodedChar); return decodedChar; } private CharsetEncoder getUtf8Encoder() { CharsetEncoder encoder = StandardCharsets.UTF_8.newEncoder(); encoder.onMalformedInput(CodingErrorAction.REPORT); encoder.onUnmappableCharacter(CodingErrorAction.REPORT); return encoder; } private CharsetDecoder getUtf8Decoder() { CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPORT); decoder.onUnmappableCharacter(CodingErrorAction.REPORT); return decoder; } private byte[] base64Decode(String internalStringValue) { return Base64.getDecoder().decode(internalStringValue); } private String base64Encode(byte[] encryptedBytes) { return Base64.getEncoder().encodeToString(encryptedBytes); } @Override public char[] decryptAes(char[] encryptedValue) throws KuraException { if (encryptedValue.length == 0) { return new char[0]; } try { String internalStringValue = new String(encryptedValue); String[] internalStringValueArray = internalStringValue.split(ENCRYPTED_STRING_SEPARATOR); if (internalStringValueArray.length != 2) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } String encodedIv = internalStringValueArray[0]; String encodedValue = internalStringValueArray[1]; byte[] iv = base64Decode(encodedIv); byte[] decodedValue = base64Decode(encodedValue); if (encryptedValue.length > 0 && decodedValue.length == 0) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } Cipher c = Cipher.getInstance(CIPHER); c.init(Cipher.DECRYPT_MODE, generateKey(), new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv)); byte[] decryptedBytes = c.doFinal(decodedValue); return byteArrayToCharArray(decryptedBytes); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, DECRYPT_EXCEPTION_CAUSE); } catch (InvalidKeyException | BadPaddingException | IllegalBlockSizeException | CharacterCodingException e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } catch (InvalidAlgorithmParameterException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE); } } @Override public InputStream aesDecryptingStream(InputStream encryptedStream) throws KuraException { try { final BufferedInputStream buffered = new BufferedInputStream(encryptedStream); final ByteArrayOutputStream encodedIv = new ByteArrayOutputStream(); int b; for (b = buffered.read(); b != -1 && b != '-'; b = buffered.read()) { encodedIv.write(b); } if (b == -1) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } byte[] iv = base64Decode(new String(encodedIv.toByteArray(), StandardCharsets.UTF_8)); buffered.mark(1); if (buffered.read() == -1) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } buffered.reset(); final InputStream decodedStream = Base64.getDecoder().wrap(buffered); Cipher c = Cipher.getInstance(CIPHER); c.init(Cipher.DECRYPT_MODE, generateKey(), new GCMParameterSpec(AUTH_TAG_LENGTH_BIT, iv)); return new CipherInputStream(decodedStream, c); } catch (IOException e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, e); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED, DECRYPT_EXCEPTION_CAUSE); } catch (InvalidKeyException e) { throw new KuraException(KuraErrorCode.DECODER_ERROR, VALUE_EXCEPTION_CAUSE); } catch (InvalidAlgorithmParameterException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, PARAMETER_EXCEPTION_CAUSE); } } @Override @Deprecated public String encryptAes(String value) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { char[] encryptedValue = null; try { encryptedValue = encryptAes(value.toCharArray()); } catch (KuraException e) { Throwable t = e.getCause(); if (t instanceof NoSuchAlgorithmException) { throw (NoSuchAlgorithmException) t; } else if (t instanceof NoSuchPaddingException) { throw (NoSuchPaddingException) t; } else if (t instanceof InvalidKeyException) { throw (InvalidKeyException) t; } else if (t instanceof IllegalBlockSizeException) { throw (IllegalBlockSizeException) t; } else if (t instanceof BadPaddingException) { throw (BadPaddingException) t; } } return new String(encryptedValue); } @Override @Deprecated public String decryptAes(String encryptedValue) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException, BadPaddingException { try { return new String(decryptAes(encryptedValue.toCharArray())); } catch (KuraException e) { throw new IOException(); } } @Override public String encodeBase64(String stringValue) throws UnsupportedEncodingException { if (stringValue == null) { return null; } return base64Encode(stringValue.getBytes(StandardCharsets.UTF_8)); } @Override public String decodeBase64(String encodedValue) throws NoSuchAlgorithmException, UnsupportedEncodingException { if (encodedValue == null) { return null; } return new String(base64Decode(encodedValue), StandardCharsets.UTF_8); } @Override public char[] getKeyStorePassword(String keyStorePath) { Properties props = new Properties(); char[] password = null; File f = new File(this.keystorePasswordPath); if (!f.exists()) { return "changeit".toCharArray(); } try (FileInputStream fis = new FileInputStream(this.keystorePasswordPath);) { props.load(fis); Object value = props.get(keyStorePath); if (value != null) { String encryptedPassword = (String) value; password = decryptAes(encryptedPassword.toCharArray()); } } catch (FileNotFoundException e) { logger.warn("File not found exception while getting keystore password - ", e); } catch (IOException e) { logger.warn("IOException while getting keystore password - ", e); } catch (KuraException e) { logger.warn("KuraException while getting keystore password - ", e); } return password; } @Override public void setKeyStorePassword(String keyStorePath, char[] password) throws KuraException { Properties props = new Properties(); try (FileInputStream fis = new FileInputStream(this.keystorePasswordPath)) { props.load(fis); } catch (IOException e) { // Not loading from an existing file } char[] encryptedPassword = encryptAes(password); props.put(keyStorePath, new String(encryptedPassword)); try (FileOutputStream fos = new FileOutputStream(this.keystorePasswordPath);) { props.store(fos, "Do not edit this file. It's automatically generated by Kura"); fos.flush(); } catch (IOException e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } } @Override @Deprecated public void setKeyStorePassword(String keyStorePath, String password) throws IOException { try { setKeyStorePassword(keyStorePath, password.toCharArray()); } catch (KuraException e) { throw new IOException(e); } } @Override public boolean isFrameworkSecure() { return false; } private Key generateKey() { if (!this.secretKey.isPresent()) { logger.warn("A user defined encryption key has not been provided or is invalid." + " The default well known key is in use." + " Please reinstall Kura and provide a valid encryption key of length 16, 24, or 32 bytes (characters)" + " as explained in the Eclipse Kura documentation."); return new SecretKeySpec(DEFAULT_SECRET_KEY, ALGORITHM); } return new SecretKeySpec(this.secretKey.get(), ALGORITHM); } @Override public String hash(String s, String algorithm) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest messageDigest = MessageDigest.getInstance(algorithm); messageDigest.reset(); messageDigest.update(s.getBytes(StandardCharsets.UTF_8)); byte[] encodedBytes = messageDigest.digest(); return base64Encode(encodedBytes); } } ================================================ FILE: kura/org.eclipse.kura.core.crypto/src/main/java/org/eclipse/kura/core/crypto/SystemdCredentialLoader.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.crypto; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Optional; public class SystemdCredentialLoader { private static final String CREDENTIALS_DIRECTORY_ENV = "CREDENTIALS_DIRECTORY"; private final File credentialRoot; public SystemdCredentialLoader(final File credentialRoot) { this.credentialRoot = credentialRoot; } public static Optional fromEnv() { return Optional.ofNullable(System.getenv(CREDENTIALS_DIRECTORY_ENV)).map(File::new).filter(File::isDirectory) .map(SystemdCredentialLoader::new); } public Optional loadCredential(final String name) throws IOException { final File credentialFile = new File(this.credentialRoot, name); if (!credentialFile.exists()) { return Optional.empty(); } try (final InputStream in = new FileInputStream(credentialFile); final ByteArrayOutputStream out = new ByteArrayOutputStream()) { final byte[] buf = new byte[1024]; for (int rd = in.read(buf); rd != -1; rd = in.read(buf)) { out.write(buf, 0, rd); } return Optional.of(out.toByteArray()); } } } ================================================ FILE: kura/org.eclipse.kura.core.identity/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.identity Bundle-SymbolicName: org.eclipse.kura.core.identity;singleton:=true Bundle-Version: 2.0.0.qualifier Import-Package: org.eclipse.kura;version="[1.7,2.0)", org.eclipse.kura.audit;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.crypto;version="[1.3,2.0)", org.eclipse.kura.identity;version="[1.2,1.3)", org.eclipse.kura.identity.configuration.extension;version="[1.0,2.0)", org.eclipse.kura.util.useradmin;version="[1.1,2.0)", org.eclipse.kura.util.validation;version="[1.0,2.0)", org.osgi.service.useradmin;version="1.1.0", org.slf4j;version="1.7.36" Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy ================================================ FILE: kura/org.eclipse.kura.core.identity/OSGI-INF/org.eclipse.kura.core.identity.IdentityServiceImpl.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.identity/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.identity/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.identity/build.properties ================================================ # # Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/ source.. = src/main/java/ src.includes = about.html,\ about_files/ additional.bundles = org.osgi.service.component.annotations,\ org.osgi.service.metatype.annotations ================================================ FILE: kura/org.eclipse.kura.core.identity/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.identity 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.identity.test/target/site/jacoco-aggregate/jacoco.xml biz.aQute.bnd bnd-maven-plugin ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/IdentityServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2024, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.audit.AuditContext; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.identity.store.TemporaryIdentityStore; import org.eclipse.kura.core.identity.store.TemporaryIdentityStoreAdapter; import org.eclipse.kura.core.identity.store.UserAdminIdentityStore; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.identity.AdditionalConfigurations; import org.eclipse.kura.identity.AssignedPermissions; import org.eclipse.kura.identity.IdentityConfiguration; import org.eclipse.kura.identity.IdentityConfigurationComponent; import org.eclipse.kura.identity.IdentityService; import org.eclipse.kura.identity.PasswordConfiguration; import org.eclipse.kura.identity.PasswordHash; import org.eclipse.kura.identity.PasswordStrengthVerificationService; import org.eclipse.kura.identity.Permission; import org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension; import org.eclipse.kura.util.useradmin.UserAdminHelper; import org.eclipse.kura.util.useradmin.UserAdminHelper.AuthenticationException; import org.osgi.service.useradmin.UserAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @SuppressWarnings("restriction") public class IdentityServiceImpl implements IdentityService { private static final String IDENTITY_SERVICE_FAILURE_FORMAT_STRING = "{} IdentityService - Failure - {}"; private static final String IDENTITY_SERVICE_SUCCESS_FORMAT_STRING = "{} IdentityService - Success - {}"; private static final Logger auditLogger = LoggerFactory.getLogger("AuditLogger"); private static final Logger logger = LoggerFactory.getLogger(IdentityServiceImpl.class); public static final String PASSWORD_PROPERTY = "kura.password"; public static final String KURA_NEED_PASSWORD_CHANGE = "kura.need.password.change"; private UserAdmin userAdmin; private CryptoService cryptoService; private UserAdminHelper userAdminHelper; private PasswordStrengthVerificationService passwordStrengthVerificationService; private final Map extensions = new ConcurrentHashMap<>(); private final TemporaryIdentityStore temporaryStore = new TemporaryIdentityStore(); private TemporaryIdentityStoreAdapter temporaryIdentityStore; private UserAdminIdentityStore userAdminIdentityStore; public void setCryptoService(final CryptoService cryptoService) { this.cryptoService = cryptoService; } public void setUserAdmin(final UserAdmin userAdmin) { this.userAdmin = userAdmin; } public void setPasswordStrengthVerificationService( final PasswordStrengthVerificationService passwordStrengthVerificationService) { this.passwordStrengthVerificationService = passwordStrengthVerificationService; } public synchronized void setIdentityConfigurationExtension( final IdentityConfigurationExtension identityConfigurationExtension, final Map properties) { final Object kuraServicePid = properties.get(ConfigurationService.KURA_SERVICE_PID); if (!(kuraServicePid instanceof String)) { logger.warn("found {} registered without setting the {} service property, service will not be tracked", IdentityConfigurationExtension.class.getSimpleName(), ConfigurationService.KURA_SERVICE_PID); return; } this.extensions.put((String) kuraServicePid, identityConfigurationExtension); } public synchronized void unsetIdentityConfigurationExtension( final IdentityConfigurationExtension identityConfigurationExtension, final Map properties) { final Object kuraServicePid = properties.get(ConfigurationService.KURA_SERVICE_PID); if (kuraServicePid instanceof String) { this.extensions.remove(kuraServicePid); } } public void activate() { this.userAdminHelper = new UserAdminHelper(this.userAdmin, this.cryptoService); this.temporaryIdentityStore = new TemporaryIdentityStoreAdapter(this.temporaryStore, this.passwordStrengthVerificationService, this::computePasswordHash); this.userAdminIdentityStore = new UserAdminIdentityStore(this.userAdminHelper, this.extensions, logger, this::computePasswordHash); } public void deactivate() { this.temporaryStore.shutdown(); } @Override public synchronized boolean createIdentity(final String name) throws KuraException { ValidationUtil.validateNewIdentityName(name); return createIdentity(new IdentityConfiguration(name, Collections.emptyList())); } @Override public synchronized boolean createIdentity(final IdentityConfiguration configuration) throws KuraException { final String name = configuration.getName(); ValidationUtil.validateNewIdentityName(name); if (this.temporaryIdentityStore.exists(name) || this.userAdminHelper.getUser(name).isPresent()) { return false; } audit(() -> { this.userAdminHelper.createUser(name); if (!configuration.getComponents().isEmpty()) { validateIdentityConfiguration(configuration); this.userAdminIdentityStore.updateIdentityConfiguration(configuration); } }, "Create identity " + name); return true; } @Override public synchronized boolean deleteIdentity(final String name) throws KuraException { if (this.temporaryIdentityStore.exists(name)) { return audit(() -> this.temporaryIdentityStore.deleteIdentity(name), "Delete temporary identity " + name); } if (this.userAdminIdentityStore.exists(name)) { return audit(() -> this.userAdminIdentityStore.deleteIdentity(name), "Delete identity " + name); } return false; } @Override public synchronized List getIdentitiesConfiguration( Set> componentsToReturn) throws KuraException { final List result = new ArrayList<>(); result.addAll(this.userAdminIdentityStore.getIdentitiesConfiguration(componentsToReturn)); result.addAll(this.temporaryIdentityStore.getIdentitiesConfiguration(componentsToReturn)); return result; } @Override public synchronized Optional getIdentityConfiguration(String name, Set> componentsToReturn) throws KuraException { final Optional temporaryIdentity = this.temporaryIdentityStore .getIdentityConfiguration(name, componentsToReturn); if (temporaryIdentity.isPresent()) { return temporaryIdentity; } return this.userAdminIdentityStore.getIdentityConfiguration(name, componentsToReturn); } @Override public IdentityConfiguration getIdentityDefaultConfiguration(String identityName, Set> componentsToReturn) throws KuraException { final List components = new ArrayList<>(); if (componentsToReturn.contains(PasswordConfiguration.class)) { components.add(new PasswordConfiguration(false, false, Optional.empty(), Optional.empty())); } if (componentsToReturn.contains(AssignedPermissions.class)) { components.add(new AssignedPermissions(Collections.emptySet())); } if (componentsToReturn.contains(AdditionalConfigurations.class)) { components.add(getAdditionalConfigurationsDefaults(identityName)); } return new IdentityConfiguration(identityName, components); } @Override public void validateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException { audit(() -> { final Optional passwordCofiguration = identityConfiguration .getComponent(PasswordConfiguration.class); if (passwordCofiguration.isPresent()) { validatePasswordConfiguration(identityConfiguration, passwordCofiguration.get()); } final Optional additionalConfigurations = identityConfiguration .getComponent(AdditionalConfigurations.class); if (additionalConfigurations.isPresent()) { validateAdditionalConfigurations(identityConfiguration, additionalConfigurations.get()); } final Optional assignedPermissions = identityConfiguration .getComponent(AssignedPermissions.class); if (assignedPermissions.isPresent()) { validateAssignedPermissions(assignedPermissions.get()); } }, "Validate configuration for identity" + identityConfiguration.getName()); } @Override public synchronized void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException { audit(() -> { if (this.temporaryIdentityStore.exists(identityConfiguration.getName())) { validateIdentityConfiguration(identityConfiguration); this.temporaryIdentityStore.updateIdentityConfiguration(identityConfiguration); return; } if (!this.userAdminIdentityStore.exists(identityConfiguration.getName())) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Identity does not exist"); } validateIdentityConfiguration(identityConfiguration); this.userAdminIdentityStore.updateIdentityConfiguration(identityConfiguration); }, "Update configuration for identity " + identityConfiguration.getName()); } @Override public synchronized boolean createPermission(final Permission permission) throws KuraException { if (this.userAdminHelper.getPermission(permission.getName()).isPresent()) { return false; } ValidationUtil.validateNewPermissionName(permission.getName()); this.userAdminHelper.getOrCreatePermission(permission.getName()); return true; } @Override public synchronized boolean deletePermission(final Permission permission) throws KuraException { if (!this.userAdminHelper.getPermission(permission.getName()).isPresent()) { return false; } this.userAdminHelper.deletePremission(permission.getName()); return true; } @Override public synchronized Set getPermissions() { return new UserAdminHelper(this.userAdmin, this.cryptoService).getDefinedPermissions().stream() .map(Permission::new).collect(Collectors.toSet()); } @Override public PasswordHash computePasswordHash(final char[] password) throws KuraException { try { final String result = this.cryptoService.sha256Hash(new String(password)); for (int i = 0; i < password.length; i++) { password[i] = ' '; } return new PasswordHashImpl(result); } catch (Exception e) { throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE, "failed to compute password hash"); } } @Override public void checkPassword(String identityName, char[] password) throws KuraException { final PasswordConfiguration passwordConfiguration = getIdentityConfiguration(identityName, Collections.singleton(PasswordConfiguration.class)) .flatMap(i -> i.getComponent(PasswordConfiguration.class)) .orElseThrow(() -> new KuraException(KuraErrorCode.SECURITY_EXCEPTION)); if (!passwordConfiguration.isPasswordAuthEnabled() || !Objects.equals(passwordConfiguration.getPasswordHash(), Optional.of(computePasswordHash(password)))) { throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION, "Password authentication is not enabled or password does not match"); } } @Override public void checkPermission(String identityName, Permission permission) throws KuraException { final Optional temporaryIdentity = this.temporaryStore.getIdentity(identityName); if (temporaryIdentity.isPresent()) { final Optional assignedPermissions = temporaryIdentity.get() .getComponent(AssignedPermissions.class); if (!assignedPermissions.isPresent()) { throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION, "The specified permission is not assigned to the given identity"); } final boolean hasPermission = assignedPermissions.get().getPermissions().stream() .anyMatch(p -> Objects.equals(p.getName(), permission.getName())); if (!hasPermission) { throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION, "The specified permission is not assigned to the given identity"); } return; } try { this.userAdminHelper.requirePermissions(identityName, permission.getName()); } catch (AuthenticationException e) { throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION, "The specified permission is not assigned to the given identity"); } } private AdditionalConfigurations getAdditionalConfigurationsDefaults(final String name) { final List additionalConfigurations = new ArrayList<>(); for (final IdentityConfigurationExtension extension : this.extensions.values()) { try { extension.getDefaultConfiguration(name).ifPresent(additionalConfigurations::add); } catch (final Exception e) { logger.warn("Failed to get identity additional configuration defaults from extension", e); } } return new AdditionalConfigurations(additionalConfigurations); } private void validatePasswordConfiguration(final IdentityConfiguration identityConfiguration, final PasswordConfiguration passwordCofiguration) throws KuraException { if (!passwordCofiguration.isPasswordAuthEnabled()) { return; } final Optional newPassword = passwordCofiguration.getNewPassword(); if (newPassword.isPresent()) { ValidationUtil.validateNewPassword(identityConfiguration.getName(), newPassword.get(), passwordStrengthVerificationService); } else { final boolean hasPersistedPasswordHash = this.userAdminHelper.getUser(identityConfiguration.getName()) .filter(u -> u.getCredentials().get(PASSWORD_PROPERTY) != null).isPresent(); final boolean hasTemporaryPasswordHash = this.temporaryStore.getIdentity(identityConfiguration.getName()) .flatMap(config -> config.getComponent(PasswordConfiguration.class)) .flatMap(PasswordConfiguration::getPasswordHash).isPresent(); if (!hasPersistedPasswordHash && !hasTemporaryPasswordHash) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Password authentication is enabled but no password has been provided or is currently assigned"); } } } private void validateAssignedPermissions(final AssignedPermissions assignedPermissions) throws KuraException { for (final Permission permission : assignedPermissions.getPermissions()) { if (!this.userAdminHelper.getPermission(permission.getName()).isPresent()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Permission does not exist"); } } } private void validateAdditionalConfigurations(final IdentityConfiguration identityConfiguration, final AdditionalConfigurations additionalConfigurations) throws KuraException { for (final ComponentConfiguration config : additionalConfigurations.getConfigurations()) { final Optional extension = Optional .ofNullable(this.extensions.get(config.getPid())); if (!extension.isPresent()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Configuration extension pid is not registered"); } extension.get().validateConfiguration(identityConfiguration.getName(), config); } } @Override public synchronized void createTemporaryIdentity(final String identityName, final Duration lifetime) throws KuraException { createTemporaryIdentity(new IdentityConfiguration(identityName, Collections.emptyList()), lifetime); } @Override public synchronized void createTemporaryIdentity(final IdentityConfiguration identityConfiguration, final Duration lifetime) throws KuraException { final String identityName = identityConfiguration.getName(); ValidationUtil.validateNewIdentityName(identityName); // Check if identity already exists (temporary or regular) if (this.temporaryStore.exists(identityName)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "A temporary identity with name '" + identityName + "' already exists"); } if (this.userAdminHelper.getUser(identityName).isPresent()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "An identity with name '" + identityName + "' already exists"); } audit(() -> { if (lifetime == null || lifetime.isZero() || lifetime.isNegative()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Temporary identity lifetime must be positive"); } validateIdentityConfiguration(identityConfiguration); this.temporaryIdentityStore.createIdentity(identityConfiguration, lifetime); }, "Create temporary identity " + identityName); } public static T audit(final FallibleSupplier task, final String message) throws E { try { final T result = task.get(); auditLogger.info(IDENTITY_SERVICE_SUCCESS_FORMAT_STRING, AuditContext.currentOrInternal(), message); return result; } catch (final Exception e) { auditLogger.warn(IDENTITY_SERVICE_FAILURE_FORMAT_STRING, AuditContext.currentOrInternal(), message); throw e; } } public static void audit(final FallibleTask task, final String message) throws E { try { task.run(); auditLogger.info(IDENTITY_SERVICE_SUCCESS_FORMAT_STRING, AuditContext.currentOrInternal(), message); } catch (final Exception e) { auditLogger.warn(IDENTITY_SERVICE_FAILURE_FORMAT_STRING, AuditContext.currentOrInternal(), message); throw e; } } public interface FallibleSupplier { public T get() throws E; } public interface FallibleTask { public void run() throws E; } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/LoginBannerServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.identity; import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BooleanSupplier; import java.util.function.Supplier; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.identity.LoginBannerService; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Modified; import org.osgi.service.metatype.annotations.Designate; @Component(immediate = true, name = LoginBannerServiceOptions.PID, // configurationPolicy = ConfigurationPolicy.REQUIRE, property = "kura.ui.service.hide:Boolean=true") @Designate(ocd = LoginBannerServiceOptions.class) public class LoginBannerServiceImpl implements LoginBannerService, ConfigurableComponent { private final AtomicReference options; @Activate public LoginBannerServiceImpl(final LoginBannerServiceOptions options) { this.options = new AtomicReference<>(options); } @Modified public void updated(final LoginBannerServiceOptions options) { this.options.set(options); } @Override public Optional getPreLoginBanner() { final LoginBannerServiceOptions currentOptions = this.options.get(); return getMessage(currentOptions::pre_login_banner_enabled, currentOptions::pre_login_banner_content); } @Override public Optional getPostLoginBanner() { final LoginBannerServiceOptions currentOptions = this.options.get(); return getMessage(currentOptions::post_login_banner_enabled, currentOptions::post_login_banner_content); } private static final Optional getMessage(final BooleanSupplier enabled, final Supplier message) { if (enabled.getAsBoolean()) { return Optional.ofNullable(message.get()).map(String::trim).filter(s -> !s.isEmpty()); } else { return Optional.empty(); } } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/LoginBannerServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.identity; import org.osgi.service.component.annotations.ComponentPropertyType; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; @ObjectClassDefinition(id = LoginBannerServiceOptions.PID, name = "Login Banner", // description = "This component allows to enable and configure pre and post login banners that can be shown by Kura user interfaces.") @ComponentPropertyType public @interface LoginBannerServiceOptions { public static final String PID = "org.eclipse.kura.identity.LoginBannerService"; @AttributeDefinition(name = "Pre Login Banner Enabled", // description = "If enabled, a customizable banner will be shown before user login.") public boolean pre_login_banner_enabled() default true; @AttributeDefinition(name = "Pre Login Banner Content", // description = "The message to be shown in the pre login banner, if the feature is enabled.|TextArea") public String pre_login_banner_content() default "WARNING: This is a secure system. The details of this login attempt have been recorded for future inspection by the system administrator. Log out now if you are not authorized to use this device."; @AttributeDefinition(name = "Post Login Banner Enabled", // description = "If enabled, a customizable banner will be shown after successful user login.") public boolean post_login_banner_enabled() default false; @AttributeDefinition(name = "Post Login Banner Content", // description = "The message to be shown in the post login banner, if the feature is enabled.|TextArea") public String post_login_banner_content() default "Sample Banner Content"; } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordHashImpl.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.identity; import java.util.Objects; import org.eclipse.kura.identity.PasswordHash; public class PasswordHashImpl implements PasswordHash { private final String hash; public PasswordHashImpl(String hash) { super(); this.hash = hash; } @Override public int hashCode() { return Objects.hash(this.hash); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PasswordHashImpl)) { return false; } PasswordHashImpl other = (PasswordHashImpl) obj; return Objects.equals(this.hash, other.hash); } @Override public String toString() { return this.hash; } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordHasher.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity; import org.eclipse.kura.KuraException; import org.eclipse.kura.identity.PasswordHash; public interface PasswordHasher { PasswordHash hash(char[] password) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordStrengthVerificationServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.identity; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.identity.PasswordStrengthRequirements; import org.eclipse.kura.identity.PasswordStrengthVerificationService; import org.eclipse.kura.util.validation.PasswordStrengthValidators; import org.eclipse.kura.util.validation.Validator; import org.eclipse.kura.util.validation.ValidatorOptions; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.ConfigurationPolicy; import org.osgi.service.component.annotations.Modified; import org.osgi.service.metatype.annotations.Designate; @SuppressWarnings("restriction") @Component(immediate = true, name = PasswordStrengthVerificationServiceOptions.PID, // configurationPolicy = ConfigurationPolicy.REQUIRE, property = "kura.ui.service.hide:Boolean=true") @Designate(ocd = PasswordStrengthVerificationServiceOptions.class) public class PasswordStrengthVerificationServiceImpl implements PasswordStrengthVerificationService, ConfigurableComponent { private final AtomicReference requirements; @Activate public PasswordStrengthVerificationServiceImpl(final PasswordStrengthVerificationServiceOptions options) { this.requirements = new AtomicReference<>(buildPasswordStrengthRequirements(options)); } @Modified public void updated(final PasswordStrengthVerificationServiceOptions options) { this.requirements.set(buildPasswordStrengthRequirements(options)); } @Override public PasswordStrengthRequirements getPasswordStrengthRequirements() { return this.requirements.get(); } @Override public void checkPasswordStrength(char[] password) throws KuraException { List> validators = buildValidators(null); checkPasswordStrength(password, validators); } @Override public void checkPasswordStrength(String identityName, char[] password) throws KuraException { List> validators = buildValidators(identityName); checkPasswordStrength(password, validators); } private List> buildValidators(String identityName) { PasswordStrengthRequirements currentRequirements = getPasswordStrengthRequirements(); ValidatorOptions validatorOptions = new ValidatorOptions(currentRequirements.getPasswordMinimumLength(), // currentRequirements.digitsRequired(), // currentRequirements.bothCasesRequired(), // currentRequirements.specialCharactersRequired()); List> validators = new ArrayList<>(PasswordStrengthValidators.fromConfig(validatorOptions)); if (identityName != null && !identityName.trim().isEmpty()) { validators.add(PasswordStrengthValidators.requireDifferentNameAndPassword(identityName)); } return validators; } private void checkPasswordStrength(char[] password, List> validators) throws KuraException { final List errors = new ArrayList<>(); for (final Validator validator : validators) { validator.validate(new String(password), errors::add); } if (!errors.isEmpty()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Password strength requirements not satisfied: " + errors.stream().collect(Collectors.joining("; "))); } } private static PasswordStrengthRequirements buildPasswordStrengthRequirements( final PasswordStrengthVerificationServiceOptions options) { return new PasswordStrengthRequirements(options.new_password_min_length(), options.new_password_require_digits(), options.new_password_require_special_characters(), options.new_password_require_both_cases()); } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/PasswordStrengthVerificationServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.identity; import org.osgi.service.component.annotations.ComponentPropertyType; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.ObjectClassDefinition; @ObjectClassDefinition(id = PasswordStrengthVerificationServiceOptions.PID, name = "Password Strength", // description = "This component allows to configure the strength requirements for new passwords.") @ComponentPropertyType public @interface PasswordStrengthVerificationServiceOptions { public static final String PID = "org.eclipse.kura.identity.PasswordStrengthVerificationService"; @AttributeDefinition(name = "Minimum password length", // min = "0", // description = "The minimum length to be enforced for new passwords. Set to 0 to disable.") public int new_password_min_length() default 12; @AttributeDefinition(name = "Require digits in new password", // description = "If set to true, new passwords will be accepted only if containing at least one digit.") public boolean new_password_require_digits() default true; @AttributeDefinition(name = "Require special characters in new password", // description = "If set to true, new passwords will be accepted only if containing at least one non alphanumeric character.") public boolean new_password_require_special_characters() default true; @AttributeDefinition(name = "Require uppercase and lowercase characters in new passwords", // description = "If set to true, new passwords will be accepted only if containing both" + " uppercase and lowercase alphanumeric characters.") public boolean new_password_require_both_cases() default true; } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/ValidationUtil.java ================================================ /******************************************************************************* * Copyright (c) 2024, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.identity; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.identity.PasswordStrengthVerificationService; public class ValidationUtil { private static final String NEW_PASSWORD = "New password"; private static final String PERMISSION_NAME = "Permission name"; private static final String IDENTITY_NAME = "Identity name"; private ValidationUtil() { } public static void validateNewPassword(final char[] password, final PasswordStrengthVerificationService passwordStrengthVerificationService) throws KuraException { if (password == null || password.length == 0) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "New password cannot be empty"); } requireMaximumLength(NEW_PASSWORD, password, 255); requireNoWhitespaceCharacters(NEW_PASSWORD, password); passwordStrengthVerificationService.checkPasswordStrength(password); } public static void validateNewPassword(String identityName, final char[] password, final PasswordStrengthVerificationService passwordStrengthVerificationService) throws KuraException { if (password == null || password.length == 0) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "New password cannot be empty"); } requireMaximumLength(NEW_PASSWORD, password, 255); requireNoWhitespaceCharacters(NEW_PASSWORD, password); passwordStrengthVerificationService.checkPasswordStrength(identityName, password); } public static void validateNewIdentityName(final String identityName) throws KuraException { requireMinimumLength(IDENTITY_NAME, identityName, 3); requireMaximumLength(IDENTITY_NAME, identityName, 255); new PunctuatedAlphanumericSequenceValidator(IDENTITY_NAME, Arrays.asList('.', '_')).validate(identityName); } public static void validateNewPermissionName(final String permissionName) throws KuraException { requireMinimumLength(PERMISSION_NAME, permissionName, 3); requireMaximumLength(PERMISSION_NAME, permissionName, 255); new PunctuatedAlphanumericSequenceValidator(PERMISSION_NAME, Collections.singletonList('.')) .validate(permissionName); } private static void requireMinimumLength(final String parameterName, final String value, final int length) throws KuraException { if (value.length() < length) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName + " name must be at least " + length + " characters long"); } } private static void requireMaximumLength(final String parameterName, final String value, final int length) throws KuraException { if (value.length() > length) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName + " must be at most " + length + " characters long"); } } private static void requireMaximumLength(final String parameterName, final char[] value, final int length) throws KuraException { if (value.length > length) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName + " must be at most " + length + " characters long"); } } private static void requireNoWhitespaceCharacters(final String parameterName, final char[] value) throws KuraException { for (int i = 0; i < value.length; i++) { if (Character.isWhitespace(value[i])) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName + " cannot contain whitespace characters"); } } } private static class PunctuatedAlphanumericSequenceValidator { private final String parameterName; private final List delimiters; private static final Pattern ALPHANUMERIC_PATTERN = Pattern.compile("[a-zA-Z0-9]+"); public PunctuatedAlphanumericSequenceValidator(final String parameterName, final List delimiters) { this.parameterName = parameterName; this.delimiters = delimiters; } private boolean isDelimiter(final char value) { for (final char delimiter : delimiters) { if (value == delimiter) { return true; } } return false; } private void requireNonEmptyAlphanumericString(final String value) throws KuraException { if (!ALPHANUMERIC_PATTERN.matcher(value).matches()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, parameterName + " must be composed of one or more non empty alphanumeric characters sequences separated by the following characters: " + delimiters.stream().map(c -> "\'" + c + "\'").collect(Collectors.joining(" "))); } } public void validate(final String value) throws KuraException { if (value.isEmpty()) { return; } final StringBuilder component = new StringBuilder(); for (int i = 0; i < value.length(); i++) { final char c = value.charAt(i); if (isDelimiter(c)) { requireNonEmptyAlphanumericString(component.toString()); component.setLength(0); } else { component.append(c); } } requireNonEmptyAlphanumericString(component.toString()); } } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/IdentityStore.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity.store; import java.util.List; import java.util.Optional; import java.util.Set; import org.eclipse.kura.KuraException; import org.eclipse.kura.identity.IdentityConfiguration; import org.eclipse.kura.identity.IdentityConfigurationComponent; interface IdentityStore { boolean exists(String identityName) throws KuraException; Optional getIdentityConfiguration(String identityName, Set> componentsToReturn) throws KuraException; List getIdentitiesConfiguration( Set> componentsToReturn) throws KuraException; void updateIdentityConfiguration(IdentityConfiguration identityConfiguration) throws KuraException; boolean deleteIdentity(String identityName) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/TemporaryIdentityStore.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity.store; import java.time.Duration; import java.time.Instant; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.eclipse.kura.identity.IdentityConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * In-memory store for temporary identities that are not persisted. * Temporary identities use the same IdentityConfiguration structure as regular identities * but are stored in-memory only and have automatic expiration. */ public class TemporaryIdentityStore { private static final Logger logger = LoggerFactory.getLogger(TemporaryIdentityStore.class); private final Map identities = new ConcurrentHashMap<>(); private final ScheduledExecutorService expirationScheduler; /** * Record storing a temporary identity configuration and its expiration time. */ static class TemporaryIdentityRecord { final IdentityConfiguration configuration; final Instant expiration; TemporaryIdentityRecord(IdentityConfiguration configuration, Duration lifetime) { this.configuration = configuration; this.expiration = Instant.now().plus(lifetime); } TemporaryIdentityRecord(IdentityConfiguration configuration, Instant expiration) { this.configuration = configuration; this.expiration = expiration; } boolean isExpired() { return Instant.now().isAfter(expiration); } } /** * Creates a new temporary identity store with automatic expiration cleanup. */ public TemporaryIdentityStore() { this.expirationScheduler = Executors.newSingleThreadScheduledExecutor(r -> { Thread thread = new Thread(r, "TemporaryIdentityStore-Cleanup"); thread.setDaemon(true); return thread; }); // Schedule periodic cleanup every minute this.expirationScheduler.scheduleWithFixedDelay(this::cleanupExpired, 1, 1, TimeUnit.MINUTES); } /** * Creates a temporary identity with the given configuration and lifetime. * * @param name the identity name * @param configuration the identity configuration * @param lifetime the duration before automatic expiration */ public void createIdentity(String name, IdentityConfiguration configuration, Duration lifetime) { TemporaryIdentityRecord identityRecord = new TemporaryIdentityRecord(configuration, lifetime); identities.put(name, identityRecord); // Schedule individual expiration scheduleExpiration(name, lifetime); logger.info("Created temporary identity '{}' with expiration at {}", name, identityRecord.expiration); } /** * Retrieves a temporary identity configuration if it exists and is not expired. * * @param name the identity name * @return the identity configuration if found and not expired, empty otherwise */ public Optional getIdentity(String name) { TemporaryIdentityRecord identityRecord = identities.get(name); if (identityRecord == null) { return Optional.empty(); } if (identityRecord.isExpired()) { // Auto-cleanup expired identity identities.remove(name); logger.debug("Temporary identity '{}' has expired and was removed", name); return Optional.empty(); } return Optional.of(identityRecord.configuration); } /** * Checks if a temporary identity exists (and is not expired). * * @param name the identity name * @return true if the identity exists and is not expired */ public boolean exists(String name) { return getIdentity(name).isPresent(); } /** * Deletes a temporary identity. * * @param name the identity name * @return true if the identity was deleted, false if it didn't exist */ public boolean deleteIdentity(String name) { boolean removed = identities.remove(name) != null; if (removed) { logger.info("Deleted temporary identity '{}'", name); } return removed; } /** * Updates a temporary identity configuration while preserving its expiration. * * @param name the identity name * @param configuration the new configuration * @return true if the identity existed and was updated */ public boolean updateIdentity(String name, IdentityConfiguration configuration) { final TemporaryIdentityRecord identityRecord = identities.get(name); if (identityRecord == null) { return false; } if (identityRecord.isExpired()) { identities.remove(name); logger.debug("Temporary identity '{}' has expired and was removed", name); return false; } identities.put(name, new TemporaryIdentityRecord(configuration, identityRecord.expiration)); return true; } /** * Returns all temporary identity names (not expired). * * @return array of identity names */ public String[] getAllIdentityNames() { // Remove expired entries first cleanupExpired(); return identities.keySet().toArray(new String[0]); } /** * Shuts down the expiration scheduler. */ public void shutdown() { logger.info("Shutting down temporary identity store"); expirationScheduler.shutdown(); try { if (!expirationScheduler.awaitTermination(5, TimeUnit.SECONDS)) { expirationScheduler.shutdownNow(); } } catch (InterruptedException e) { expirationScheduler.shutdownNow(); Thread.currentThread().interrupt(); } identities.clear(); } /** * Schedules the expiration of a temporary identity. * * @param name the identity name * @param lifetime the duration before expiration */ private void scheduleExpiration(String name, Duration lifetime) { expirationScheduler.schedule(() -> { boolean removed = identities.remove(name) != null; if (removed) { logger.info("Temporary identity '{}' expired and was removed", name); } }, lifetime.toMillis(), TimeUnit.MILLISECONDS); } /** * Removes all expired identities. */ private void cleanupExpired() { identities.entrySet().removeIf(entry -> { boolean expired = entry.getValue().isExpired(); if (expired) { logger.debug("Cleaning up expired temporary identity '{}'", entry.getKey()); } return expired; }); } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/TemporaryIdentityStoreAdapter.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity.store; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.time.Duration; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.identity.PasswordHasher; import org.eclipse.kura.core.identity.ValidationUtil; import org.eclipse.kura.identity.IdentityConfiguration; import org.eclipse.kura.identity.IdentityConfigurationComponent; import org.eclipse.kura.identity.PasswordConfiguration; import org.eclipse.kura.identity.PasswordHash; import org.eclipse.kura.identity.PasswordStrengthVerificationService; public class TemporaryIdentityStoreAdapter implements IdentityStore { private final TemporaryIdentityStore temporaryStore; private final PasswordStrengthVerificationService passwordStrengthVerificationService; private final PasswordHasher passwordHasher; public TemporaryIdentityStoreAdapter(final TemporaryIdentityStore temporaryStore, final PasswordStrengthVerificationService passwordStrengthVerificationService, final PasswordHasher passwordHasher) { this.temporaryStore = temporaryStore; this.passwordStrengthVerificationService = passwordStrengthVerificationService; this.passwordHasher = passwordHasher; } @Override public boolean exists(final String identityName) { return this.temporaryStore.exists(identityName); } @Override public Optional getIdentityConfiguration(final String identityName, final Set> componentsToReturn) { return this.temporaryStore.getIdentity(identityName) .map(config -> filterIdentityConfiguration(config, componentsToReturn)); } @Override public List getIdentitiesConfiguration( final Set> componentsToReturn) { final List result = new ArrayList<>(); for (final String identityName : this.temporaryStore.getAllIdentityNames()) { this.temporaryStore.getIdentity(identityName) .map(config -> filterIdentityConfiguration(config, componentsToReturn)) .ifPresent(result::add); } return result; } @Override public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException { final IdentityConfiguration existingConfiguration = this.temporaryStore .getIdentity(identityConfiguration.getName()) .orElseGet(() -> new IdentityConfiguration(identityConfiguration.getName(), Collections.emptyList())); final IdentityConfiguration processedConfiguration = processConfigurationForTemporaryStorage( identityConfiguration, Optional.of(existingConfiguration)); final Map, IdentityConfigurationComponent> merged = new HashMap<>(); for (final IdentityConfigurationComponent component : existingConfiguration.getComponents()) { merged.put(component.getClass(), component); } for (final IdentityConfigurationComponent component : processedConfiguration.getComponents()) { merged.put(component.getClass(), component); } final List mergedComponents = new ArrayList<>(merged.values()); final IdentityConfiguration mergedConfiguration = new IdentityConfiguration(identityConfiguration.getName(), mergedComponents); if (!this.temporaryStore.updateIdentity(identityConfiguration.getName(), mergedConfiguration)) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Temporary identity does not exist"); } } @Override public boolean deleteIdentity(final String identityName) { return this.temporaryStore.deleteIdentity(identityName); } public void createIdentity(final IdentityConfiguration configuration, final Duration lifetime) throws KuraException { final IdentityConfiguration processedConfiguration = processConfigurationForTemporaryStorage(configuration, Optional.empty()); this.temporaryStore.createIdentity(configuration.getName(), processedConfiguration, lifetime); } private IdentityConfiguration filterIdentityConfiguration(final IdentityConfiguration configuration, final Set> componentsToReturn) { if (componentsToReturn.isEmpty()) { return new IdentityConfiguration(configuration.getName(), Collections.emptyList()); } final List filteredComponents = configuration.getComponents().stream() .filter(component -> componentsToReturn.stream().anyMatch(clazz -> clazz.isInstance(component))) .toList(); return new IdentityConfiguration(configuration.getName(), filteredComponents); } private PasswordConfiguration processPasswordForStorage(final String identityName, final PasswordConfiguration passwordConfiguration, final Optional existingPasswordHash) throws KuraException { if (!passwordConfiguration.isPasswordAuthEnabled()) { return new PasswordConfiguration( passwordConfiguration.isPasswordChangeNeeded(), false, Optional.empty(), Optional.empty()); } final Optional newPassword = passwordConfiguration.getNewPassword(); if (newPassword.isPresent()) { ValidationUtil.validateNewPassword(identityName, newPassword.get(), this.passwordStrengthVerificationService); final PasswordHash hash = this.passwordHasher.hash(newPassword.get()); return new PasswordConfiguration( passwordConfiguration.isPasswordChangeNeeded(), true, Optional.empty(), Optional.of(hash)); } if (!existingPasswordHash.isPresent()) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Password authentication is enabled but no password has been provided"); } return new PasswordConfiguration( passwordConfiguration.isPasswordChangeNeeded(), true, Optional.empty(), existingPasswordHash); } private IdentityConfiguration processConfigurationForTemporaryStorage( final IdentityConfiguration configuration, final Optional existingConfiguration) throws KuraException { final String identityName = configuration.getName(); final Optional existingPasswordHash = existingConfiguration .flatMap(config -> config.getComponent(PasswordConfiguration.class)) .flatMap(PasswordConfiguration::getPasswordHash); final List processedComponents = new ArrayList<>(); for (final IdentityConfigurationComponent component : configuration.getComponents()) { if (component instanceof PasswordConfiguration) { processedComponents.add( processPasswordForStorage(identityName, (PasswordConfiguration) component, existingPasswordHash)); } else { processedComponents.add(component); } } return new IdentityConfiguration(identityName, processedComponents); } } ================================================ FILE: kura/org.eclipse.kura.core.identity/src/main/java/org/eclipse/kura/core/identity/store/UserAdminIdentityStore.java ================================================ /******************************************************************************* * Copyright (c) 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ // Content with portions generated by generative AI platform package org.eclipse.kura.core.identity.store; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Dictionary; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ComponentConfiguration; import org.eclipse.kura.core.identity.IdentityServiceImpl; import org.eclipse.kura.core.identity.PasswordHashImpl; import org.eclipse.kura.core.identity.PasswordHasher; import org.eclipse.kura.identity.AdditionalConfigurations; import org.eclipse.kura.identity.AssignedPermissions; import org.eclipse.kura.identity.IdentityConfiguration; import org.eclipse.kura.identity.IdentityConfigurationComponent; import org.eclipse.kura.identity.PasswordConfiguration; import org.eclipse.kura.identity.Permission; import org.eclipse.kura.identity.configuration.extension.IdentityConfigurationExtension; import org.eclipse.kura.util.useradmin.UserAdminHelper; import org.osgi.service.useradmin.Role; import org.osgi.service.useradmin.User; import org.slf4j.Logger; public class UserAdminIdentityStore implements IdentityStore { private final UserAdminHelper userAdminHelper; private final Map extensions; private final Logger logger; private final PasswordHasher passwordHasher; public UserAdminIdentityStore(final UserAdminHelper userAdminHelper, final Map extensions, final Logger logger, final PasswordHasher passwordHasher) { this.userAdminHelper = userAdminHelper; this.extensions = extensions; this.logger = logger; this.passwordHasher = passwordHasher; } @Override public boolean exists(final String identityName) { return this.userAdminHelper.getUser(identityName).isPresent(); } @Override public Optional getIdentityConfiguration(final String identityName, final Set> componentsToReturn) { return this.userAdminHelper.getUser(identityName) .map(user -> buildIdentity(identityName, user, componentsToReturn)); } @Override public List getIdentitiesConfiguration( final Set> componentsToReturn) { final List result = new ArrayList<>(); this.userAdminHelper.foreachUser((name, user) -> result.add(buildIdentity(name, user, componentsToReturn))); return result; } @Override public void updateIdentityConfiguration(final IdentityConfiguration identityConfiguration) throws KuraException { final User user = this.userAdminHelper.getUser(identityConfiguration.getName()) .orElseThrow(() -> new KuraException(KuraErrorCode.INVALID_PARAMETER, "Identity does not exist")); updateIdentityConfigurationInternal(user, identityConfiguration); } @Override public boolean deleteIdentity(final String identityName) throws KuraException { if (!this.userAdminHelper.getUser(identityName).isPresent()) { return false; } this.userAdminHelper.deleteUser(identityName); return true; } private void updateIdentityConfigurationInternal(final User user, final IdentityConfiguration identity) throws KuraException { final String identityName = identity.getName(); final Optional passwordData = identity.getComponent(PasswordConfiguration.class); if (passwordData.isPresent()) { updatePassword(identityName, passwordData.get(), user); } final Optional permissions = identity.getComponent(AssignedPermissions.class); if (permissions.isPresent()) { updateAssignedPermissions(identityName, permissions.get(), user); } final Optional additionalConfigurations = identity .getComponent(AdditionalConfigurations.class); if (additionalConfigurations.isPresent()) { updateAdditionalConfigurations(identity.getName(), additionalConfigurations.get()); } } private IdentityConfiguration buildIdentity(final String name, final User user, final Set> componentsToReturn) { final List components = new ArrayList<>(); if (componentsToReturn.contains(PasswordConfiguration.class)) { components.add(getPasswordData(user)); } if (componentsToReturn.contains(AssignedPermissions.class)) { final Set permissions = this.userAdminHelper.getIdentityPermissions(name).stream() .map(Permission::new).collect(Collectors.toSet()); components.add(new AssignedPermissions(permissions)); } if (componentsToReturn.contains(AdditionalConfigurations.class)) { components.add(getAdditionalConfigurations(name)); } return new IdentityConfiguration(name, components); } private AdditionalConfigurations getAdditionalConfigurations(final String name) { final List additionalConfigurations = new ArrayList<>(); for (final IdentityConfigurationExtension extension : this.extensions.values()) { try { extension.getConfiguration(name).ifPresent(additionalConfigurations::add); } catch (final Exception e) { this.logger.warn("Failed to get identity additional configuration from extension", e); } } return new AdditionalConfigurations(additionalConfigurations); } private PasswordConfiguration getPasswordData(final User user) { final Optional passwordHash = Optional.ofNullable(user.getCredentials() .get(IdentityServiceImpl.PASSWORD_PROPERTY)) .filter(String.class::isInstance).map(String.class::cast); final boolean isPasswordChangeNeeded = Objects.equals("true", user.getProperties().get(IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE)); return new PasswordConfiguration(isPasswordChangeNeeded, passwordHash.isPresent(), Optional.empty(), passwordHash.map(PasswordHashImpl::new)); } private void updateAssignedPermissions(final String identityName, final AssignedPermissions assignedPermissions, final User user) { this.userAdminHelper.foreachPermission((name, group) -> { final Permission permission = new Permission(name); final List members = Optional.ofNullable(group.getMembers()).map(Arrays::asList) .orElse(Collections.emptyList()); if (assignedPermissions.getPermissions().contains(permission) && !members.contains(user)) { IdentityServiceImpl.audit(() -> group.addMember(user), "Add permission " + permission.getName() + " to identity " + identityName); } else if (!assignedPermissions.getPermissions().contains(permission) && members.contains(user)) { IdentityServiceImpl.audit(() -> group.removeMember(user), "Remove permission " + permission.getName() + " from identity " + identityName); } }); } private void updatePassword(final String identityName, final PasswordConfiguration passwordData, final User user) throws KuraException { final Dictionary properties = user.getProperties(); final Object currentIsPasswordChangeNeeded = properties.get(IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE); if (passwordData.isPasswordChangeNeeded()) { if (!"true".equals(currentIsPasswordChangeNeeded)) { IdentityServiceImpl.audit(() -> setProperty(properties, IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE, "true"), "Enable password change at next login for identity " + identityName); } } else if (currentIsPasswordChangeNeeded != null) { IdentityServiceImpl.audit(() -> removeProperty(properties, IdentityServiceImpl.KURA_NEED_PASSWORD_CHANGE), "Disable password change at next login for identity " + identityName); } final Dictionary credentials = user.getCredentials(); final Optional newPassword = passwordData.getNewPassword(); final Object currentPasswordHash = credentials.get(IdentityServiceImpl.PASSWORD_PROPERTY); if (passwordData.isPasswordAuthEnabled() && newPassword.isPresent()) { IdentityServiceImpl.audit(() -> setProperty(credentials, IdentityServiceImpl.PASSWORD_PROPERTY, this.passwordHasher.hash(newPassword.get()).toString()), "Update Kura password for identity " + identityName); } else if (!passwordData.isPasswordAuthEnabled() && currentPasswordHash != null) { IdentityServiceImpl.audit(() -> removeProperty(credentials, IdentityServiceImpl.PASSWORD_PROPERTY), "Disable Kura password for identity " + identityName); } } private void updateAdditionalConfigurations(final String identityName, final AdditionalConfigurations additionalConfigurations) throws KuraException { final FailureHandler failureHandler = new FailureHandler(this.logger); for (final ComponentConfiguration config : additionalConfigurations.getConfigurations()) { final String pid = config.getPid(); final Optional extension = Optional.ofNullable(this.extensions.get(pid)); if (!extension.isPresent()) { failureHandler.addError("Configuration extension pid is not registered"); continue; } try { IdentityServiceImpl.audit(() -> extension.get().updateConfiguration(identityName, config), "Update configuration for extension " + pid + " for identity " + identityName); } catch (final KuraException e) { failureHandler.addError(e.getMessage()); } } failureHandler.throwIfFailuresOccurred(KuraErrorCode.CONFIGURATION_ERROR); } private void setProperty(final Dictionary properties, final String key, final Object value) { if (!Objects.equals(properties.get(key), value)) { properties.put(key, value); } } private void removeProperty(final Dictionary properties, final String key) { if (properties.get(key) != null) { properties.remove(key); } } private static final class FailureHandler { private final Set errors = new HashSet<>(); private final Logger logger; private FailureHandler(final Logger logger) { this.logger = logger; } private void addError(final String message) { this.errors.add(message); this.logger.error(message); } private void throwIfFailuresOccurred(final KuraErrorCode errorCode) throws KuraException { if (!this.errors.isEmpty()) { throw new KuraException(errorCode, this.errors.stream().collect(Collectors.joining("; "))); } } } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/.gitignore ================================================ /target /bin ================================================ FILE: kura/org.eclipse.kura.core.inventory/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.inventory Bundle-SymbolicName: org.eclipse.kura.core.inventory;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: org.apache.commons.io;version="1.4.9999", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.request;version="[1.0,1.1)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.container.orchestration;version="[1.0,2.0)", org.eclipse.kura.marshalling;version="[1.0,2.0)", org.eclipse.kura.message;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.5,2.0)", org.eclipse.kura.util.service;version="[1.0,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.osgi.service.deploymentadmin;version="1.0.0", org.slf4j;version="1.6.4" Export-Package: org.eclipse.kura.core.inventory;version="1.1.0";x-internal:=true, org.eclipse.kura.core.inventory.resources;version="1.0.0";x-internal:=true ================================================ FILE: kura/org.eclipse.kura.core.inventory/OSGI-INF/inventory.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.inventory/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.inventory/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.inventory/build.properties ================================================ # # Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/ source.. = src/main/java/ additional.bundles = org.eclipse.kura.api,\ slf4j.api,\ org.eclipse.osgi src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.inventory/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.inventory 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.inventory.test/target/site/jacoco-aggregate/jacoco.xml org.apache.maven.plugins maven-checkstyle-plugin true ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/InventoryHandlerV1.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.inventory; import static org.eclipse.kura.cloudconnection.request.RequestHandlerMessageConstants.ARGS_KEY; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraProcessExecutionErrorException; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.request.RequestHandler; import org.eclipse.kura.cloudconnection.request.RequestHandlerContext; import org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor; import org.eclipse.kura.container.orchestration.ContainerOrchestrationService; import org.eclipse.kura.container.orchestration.ImageInstanceDescriptor; import org.eclipse.kura.core.inventory.resources.ContainerImage; import org.eclipse.kura.core.inventory.resources.ContainerImages; import org.eclipse.kura.core.inventory.resources.DockerContainer; import org.eclipse.kura.core.inventory.resources.DockerContainers; import org.eclipse.kura.core.inventory.resources.SystemBundle; import org.eclipse.kura.core.inventory.resources.SystemBundleRef; import org.eclipse.kura.core.inventory.resources.SystemBundles; import org.eclipse.kura.core.inventory.resources.SystemDeploymentPackage; import org.eclipse.kura.core.inventory.resources.SystemDeploymentPackages; import org.eclipse.kura.core.inventory.resources.SystemPackage; import org.eclipse.kura.core.inventory.resources.SystemPackages; import org.eclipse.kura.core.inventory.resources.SystemResourcesInfo; import org.eclipse.kura.marshalling.Marshaller; import org.eclipse.kura.marshalling.Unmarshaller; import org.eclipse.kura.message.KuraPayload; import org.eclipse.kura.message.KuraResponsePayload; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; import org.eclipse.kura.system.SystemService; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.osgi.service.deploymentadmin.BundleInfo; import org.osgi.service.deploymentadmin.DeploymentAdmin; import org.osgi.service.deploymentadmin.DeploymentPackage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class InventoryHandlerV1 implements ConfigurableComponent, RequestHandler { private static final Logger logger = LoggerFactory.getLogger(InventoryHandlerV1.class); public static final String APP_ID = "INVENTORY-V1"; public static final String RESOURCE_DEPLOYMENT_PACKAGES = "deploymentPackages"; public static final String RESOURCE_BUNDLES = "bundles"; public static final String RESOURCE_SYSTEM_PACKAGES = "systemPackages"; public static final String RESOURCE_DOCKER_CONTAINERS = "containers"; public static final String RESOURCE_CONTAINER_IMAGES = "images"; public static final String INVENTORY = "inventory"; private static final String START = "_start"; private static final String STOP = "_stop"; private static final String DELETE = "_delete"; public static final List START_BUNDLE = Arrays.asList(RESOURCE_BUNDLES, START); public static final List STOP_BUNDLE = Arrays.asList(RESOURCE_BUNDLES, STOP); public static final List START_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, START); public static final List STOP_CONTAINER = Arrays.asList(RESOURCE_DOCKER_CONTAINERS, STOP); public static final List DELETE_IMAGE = Arrays.asList(RESOURCE_CONTAINER_IMAGES, DELETE); private static final String CANNOT_FIND_RESOURCE_MESSAGE = "Cannot find resource with name: {}"; private static final String NONE_RESOURCE_FOUND_MESSAGE = "Expected one resource but found none"; private static final String BAD_REQUEST_TOPIC_MESSAGE = "Bad request topic: {}"; private static final String ERROR_GETTING_RESOURCE = "Error getting resource {}"; private static final String MISSING_MESSAGE_BODY = "missing message body"; private DeploymentAdmin deploymentAdmin; private SystemService systemService; private BundleContext bundleContext; private ContainerOrchestrationService containerOrchestrationService; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setContainerOrchestrationService(ContainerOrchestrationService containerOrchestrationService) { this.containerOrchestrationService = containerOrchestrationService; } public void unsetContainerOrchestrationService(ContainerOrchestrationService containerOrchestrationService) { if (this.containerOrchestrationService == containerOrchestrationService) { this.containerOrchestrationService = null; } } protected void setDeploymentAdmin(DeploymentAdmin deploymentAdmin) { this.deploymentAdmin = deploymentAdmin; } protected void unsetDeploymentAdmin(DeploymentAdmin deploymentAdmin) { if (this.deploymentAdmin == deploymentAdmin) { this.deploymentAdmin = null; } } public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { if (this.systemService == systemService) { this.systemService = null; } } public void setRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) { try { requestHandlerRegistry.registerRequestHandler(APP_ID, this); } catch (KuraException e) { logger.info("Unable to register cloudlet {} in {}", APP_ID, requestHandlerRegistry.getClass().getName()); } } public void unsetRequestHandlerRegistry(RequestHandlerRegistry requestHandlerRegistry) { try { requestHandlerRegistry.unregister(APP_ID); } catch (KuraException e) { logger.info("Unable to register cloudlet {} in {}", APP_ID, requestHandlerRegistry.getClass().getName()); } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { logger.info("Inventory v1 is starting"); this.bundleContext = componentContext.getBundleContext(); } protected void deactivate() { logger.info("Bundle {} is deactivating!", APP_ID); this.bundleContext = null; } // ---------------------------------------------------------------- // // Public methods // // ---------------------------------------------------------------- @Override public KuraMessage doGet(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { List resources = extractResources(reqMessage); KuraPayload resPayload; if (resources.get(0).equals(INVENTORY)) { resPayload = doGetInventory(); } else if (resources.get(0).equals(RESOURCE_DEPLOYMENT_PACKAGES)) { resPayload = doGetPackages(); } else if (resources.get(0).equals(RESOURCE_BUNDLES)) { resPayload = doGetBundles(); } else if (resources.get(0).equals(RESOURCE_SYSTEM_PACKAGES)) { resPayload = doGetSystemPackages(); } else if (resources.get(0).equals(RESOURCE_DOCKER_CONTAINERS)) { resPayload = doGetDockerContainers(); } else if (resources.get(0).equals(RESOURCE_CONTAINER_IMAGES)) { resPayload = doGetContainerImages(); } else { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(CANNOT_FIND_RESOURCE_MESSAGE, resources.get(0)); throw new KuraException(KuraErrorCode.NOT_FOUND); } return new KuraMessage(resPayload); } @SuppressWarnings("unchecked") private List extractResources(KuraMessage reqMessage) throws KuraException { Object requestObject = reqMessage.getProperties().get(ARGS_KEY.value()); List resources; if (requestObject instanceof List) { resources = (List) requestObject; } else { throw new KuraException(KuraErrorCode.BAD_REQUEST); } if (resources.isEmpty()) { logger.error(BAD_REQUEST_TOPIC_MESSAGE, resources); logger.error(NONE_RESOURCE_FOUND_MESSAGE); throw new KuraException(KuraErrorCode.BAD_REQUEST); } return resources; } @Override public KuraMessage doExec(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { final List resources = extractResources(reqMessage); try { if (START_BUNDLE.equals(resources)) { findFirstMatchingBundle(extractBundleRef(reqMessage)).start(); return success(); } else if (STOP_BUNDLE.equals(resources)) { findFirstMatchingBundle(extractBundleRef(reqMessage)).stop(); return success(); } else if (START_CONTAINER.equals(resources)) { if (this.containerOrchestrationService == null) { return notFound(); } this.containerOrchestrationService .startContainer(findFirstMatchingContainer(extractContainerRef(reqMessage)).getContainerId()); return success(); } else if (STOP_CONTAINER.equals(resources)) { if (this.containerOrchestrationService == null) { return notFound(); } this.containerOrchestrationService .stopContainer(findFirstMatchingContainer(extractContainerRef(reqMessage)).getContainerId()); return success(); } else if (DELETE_IMAGE.equals(resources)) { if (this.containerOrchestrationService == null) { return notFound(); } this.containerOrchestrationService .deleteImage(findFirstMatchingImage(extractContainerImageRef(reqMessage)).getImageId()); return success(); } } catch (final KuraException e) { throw e; } catch (final Exception e) { logger.debug("unexpected exception dispatcing call", e); // this should result in response code 500 throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE); } throw new KuraException(KuraErrorCode.NOT_FOUND); } @Override public KuraMessage doDel(RequestHandlerContext requestContext, KuraMessage reqMessage) throws KuraException { throw new KuraException(KuraErrorCode.NOT_FOUND); } // ---------------------------------------------------------------- // // Private methods // // ---------------------------------------------------------------- private KuraPayload doGetPackages() { DeploymentPackage[] dps = this.deploymentAdmin.listDeploymentPackages(); SystemDeploymentPackages xdps = new SystemDeploymentPackages(); SystemDeploymentPackage[] axdp = new SystemDeploymentPackage[dps.length]; for (int i = 0; i < dps.length; i++) { DeploymentPackage dp = dps[i]; BundleInfo[] bis = dp.getBundleInfos(); SystemBundle[] axbi = new SystemBundle[bis.length]; boolean dpSigned = true; for (int j = 0; j < bis.length; j++) { BundleInfo bi = bis[j]; SystemBundle xb = new SystemBundle(bi.getSymbolicName(), bi.getVersion().toString()); Bundle[] bundles = this.bundleContext.getBundles(); Optional bundle = Arrays.asList(bundles).stream() .filter(b -> b.getSymbolicName().equals(bi.getSymbolicName())).findFirst(); if (bundle.isPresent()) { boolean bundleSigned = true; if (bundle.get().getSignerCertificates(Bundle.SIGNERS_ALL).isEmpty()) { bundleSigned = false; dpSigned = false; } xb.setId(bundle.get().getBundleId()); xb.setState(bundleStateToString(bundle.get().getState())); xb.setSigned(bundleSigned); } axbi[j] = xb; } SystemDeploymentPackage xdp = new SystemDeploymentPackage(dp.getName(), dp.getVersion().toString()); xdp.setBundleInfos(axbi); xdp.setSigned(dpSigned); axdp[i] = xdp; } xdps.setDeploymentPackages(axdp); KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { String s = marshal(xdps); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { logger.error("Error getting resource {}: {}", RESOURCE_DEPLOYMENT_PACKAGES, e); } return respPayload; } private KuraPayload doGetBundles() { Bundle[] bundles = this.bundleContext.getBundles(); SystemBundles systemBundles = new SystemBundles(); SystemBundle[] axb = new SystemBundle[bundles.length]; for (int i = 0; i < bundles.length; i++) { Bundle bundle = bundles[i]; SystemBundle systemBundle = new SystemBundle(bundle.getSymbolicName(), bundle.getVersion().toString()); systemBundle.setId(bundle.getBundleId()); int state = bundle.getState(); systemBundle.setState(bundleStateToString(state)); systemBundle.setSigned(isSigned(bundle)); axb[i] = systemBundle; } systemBundles.setBundles(axb); KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { String s = marshal(systemBundles); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { logger.error(ERROR_GETTING_RESOURCE, RESOURCE_BUNDLES, e); } return respPayload; } private KuraPayload doGetInventory() { List inventory = new ArrayList<>(); // get System Packages try { inventory.addAll(this.systemService.getSystemPackages()); } catch (KuraProcessExecutionErrorException e) { logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e); } // get Bundles Bundle[] bundles = this.bundleContext.getBundles(); Arrays.asList(bundles).stream().forEach(b -> inventory.add( new SystemResourceInfo(b.getSymbolicName(), b.getVersion().toString(), SystemResourceType.BUNDLE))); // get Deployment Packages DeploymentPackage[] dps = this.deploymentAdmin.listDeploymentPackages(); Arrays.asList(dps).stream().forEach(dp -> inventory .add(new SystemResourceInfo(dp.getName(), dp.getVersion().toString(), SystemResourceType.DP))); // get Docker Containers if (this.containerOrchestrationService != null) { try { logger.info("Creating docker inventory"); List containers = this.containerOrchestrationService .listContainerDescriptors(); containers.stream().forEach( container -> inventory.add(new SystemResourceInfo(container.getContainerName().replace("/", ""), container.getContainerImage() + ":" + container.getContainerImageTag().split(":")[0], SystemResourceType.DOCKER))); } catch (Exception e) { logger.error("Could not connect to docker"); } } // get Container Images if (this.containerOrchestrationService != null) { try { logger.info("Creating container images inventory"); List images = this.containerOrchestrationService .listImageInstanceDescriptors(); images.stream().forEach(image -> inventory.add(new SystemResourceInfo(image.getImageName(), image.getImageTag(), SystemResourceType.CONTAINER_IMAGE))); } catch (Exception e) { logger.error("Could not connect to container-engine"); } } inventory.sort(Comparator.comparing(SystemResourceInfo::getName)); SystemResourcesInfo systemResourcesInfo = new SystemResourcesInfo(inventory); KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { String s = marshal(systemResourcesInfo); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e1) { logger.error("Error getting inventory", e1); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR); } return respPayload; } private KuraPayload doGetSystemPackages() { List systemResourceList; KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { systemResourceList = this.systemService.getSystemPackages(); List systemPackageList = new ArrayList<>(); systemResourceList.stream() .forEach(p -> systemPackageList.add(new SystemPackage(p.getName(), p.getVersion(), p.getType()))); SystemPackages systemPackages = new SystemPackages(systemPackageList); String s = marshal(systemPackages); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR); } return respPayload; } private KuraPayload doGetDockerContainers() { if (this.containerOrchestrationService == null) { return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { List containers = this.containerOrchestrationService .listContainerDescriptors(); List containersList = new ArrayList<>(); containers.stream().forEach(p -> containersList.add(new DockerContainer(p))); DockerContainers dockerContainers = new DockerContainers(containersList); String s = marshal(dockerContainers); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR); } return respPayload; } private KuraPayload doGetContainerImages() { if (this.containerOrchestrationService == null) { return new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); } KuraResponsePayload respPayload = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); try { List containers = this.containerOrchestrationService .listImageInstanceDescriptors(); List imageList = new ArrayList<>(); containers.stream().forEach(p -> imageList.add(new ContainerImage(p))); ContainerImages containerImages = new ContainerImages(imageList); String s = marshal(containerImages); respPayload.setTimestamp(new Date()); respPayload.setBody(s.getBytes(StandardCharsets.UTF_8)); } catch (Exception e) { logger.error(ERROR_GETTING_RESOURCE, RESOURCE_SYSTEM_PACKAGES, e); respPayload.setResponseCode(KuraResponsePayload.RESPONSE_CODE_ERROR); } return respPayload; } private ServiceReference[] getJsonMarshallers(final Class classz) { String filterString = String.format("(kura.service.pid=%s)", "org.eclipse.kura.json.marshaller.unmarshaller.provider"); return ServiceUtil.getServiceReferences(this.bundleContext, classz, filterString); } private void ungetServiceReferences(final ServiceReference[] refs) { ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } protected String marshal(Object object) { String result = null; ServiceReference[] marshallerSRs = getJsonMarshallers(Marshaller.class); try { for (final ServiceReference marshallerSR : marshallerSRs) { Marshaller marshaller = this.bundleContext.getService(marshallerSR); result = marshaller.marshal(object); if (result != null) { break; } } } catch (Exception e) { logger.warn("Failed to marshal configuration."); } finally { ungetServiceReferences(marshallerSRs); } return result; } public T unmarshal(final String str, final Class classz) throws KuraException { T result = null; ServiceReference[] unmarshallerSRs = getJsonMarshallers(Unmarshaller.class); try { for (final ServiceReference unmarshallerSR : unmarshallerSRs) { Unmarshaller unmarshaller = this.bundleContext.getService(unmarshallerSR); result = unmarshaller.unmarshal(str, classz); if (result != null) { return result; } } } catch (Exception e) { logger.warn("Failed to unmarshal request."); } finally { ungetServiceReferences(unmarshallerSRs); } throw new KuraException(KuraErrorCode.BAD_REQUEST); } private String bundleStateToString(int state) { String stateString; switch (state) { case Bundle.UNINSTALLED: stateString = "UNINSTALLED"; break; case Bundle.INSTALLED: stateString = "INSTALLED"; break; case Bundle.RESOLVED: stateString = "RESOLVED"; break; case Bundle.STARTING: stateString = "STARTING"; break; case Bundle.STOPPING: stateString = "STOPPING"; break; case Bundle.ACTIVE: stateString = "ACTIVE"; break; default: stateString = String.valueOf(state); } return stateString; } private boolean isSigned(Bundle bundle) { return !bundle.getSignerCertificates(Bundle.SIGNERS_ALL).isEmpty(); } private SystemBundleRef extractBundleRef(final KuraMessage message) throws KuraException { final KuraPayload payload = message.getPayload(); final byte[] body = payload.getBody(); if (body == null) { logger.warn(MISSING_MESSAGE_BODY); throw new KuraException(KuraErrorCode.BAD_REQUEST); } return unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8), SystemBundleRef.class); } private ContainerInstanceDescriptor extractContainerRef(final KuraMessage message) throws KuraException { final KuraPayload payload = message.getPayload(); final byte[] body = payload.getBody(); if (body == null) { logger.warn(MISSING_MESSAGE_BODY); throw new KuraException(KuraErrorCode.BAD_REQUEST); } DockerContainer dc = unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8), DockerContainer.class); try { List containerList = this.containerOrchestrationService .listContainerDescriptors(); for (ContainerInstanceDescriptor container : containerList) { if (container.getContainerName().equals(dc.getContainerName())) { return container; } } logger.warn("Failed to find container"); throw new KuraException(KuraErrorCode.BAD_REQUEST); } catch (Exception e) { logger.warn("failed to access docker service"); throw new KuraException(KuraErrorCode.BAD_REQUEST); } } private ImageInstanceDescriptor extractContainerImageRef(final KuraMessage message) throws KuraException { final KuraPayload payload = message.getPayload(); final byte[] body = payload.getBody(); if (body == null) { logger.warn(MISSING_MESSAGE_BODY); throw new KuraException(KuraErrorCode.BAD_REQUEST); } ContainerImage dc = unmarshal(new String(message.getPayload().getBody(), StandardCharsets.UTF_8), ContainerImage.class); try { List imageList = this.containerOrchestrationService.listImageInstanceDescriptors(); for (ImageInstanceDescriptor image : imageList) { if (image.getImageName().equals(dc.getImageName()) && image.getImageTag().equals(dc.getImageTag())) { return image; } } logger.warn("Failed to find image"); throw new KuraException(KuraErrorCode.BAD_REQUEST); } catch (Exception e) { logger.warn("failed to access docker service"); throw new KuraException(KuraErrorCode.BAD_REQUEST); } } private Bundle findFirstMatchingBundle(final SystemBundleRef ref) throws KuraException { for (final Bundle bundle : this.bundleContext.getBundles()) { if (!bundle.getSymbolicName().equals(ref.getName())) { continue; } final Optional version = ref.getVersion(); if (!version.isPresent() || version.get().equals(bundle.getVersion().toString())) { return bundle; } } throw new KuraException(KuraErrorCode.NOT_FOUND); } private ContainerInstanceDescriptor findFirstMatchingContainer(final ContainerInstanceDescriptor ref) throws KuraException { for (final ContainerInstanceDescriptor container : this.containerOrchestrationService .listContainerDescriptors()) { if (container.getContainerName().equals(ref.getContainerName())) { return container; } } throw new KuraException(KuraErrorCode.NOT_FOUND); } private ImageInstanceDescriptor findFirstMatchingImage(final ImageInstanceDescriptor ref) throws KuraException { for (final ImageInstanceDescriptor image : this.containerOrchestrationService.listImageInstanceDescriptors()) { if (image.getImageName().equals(ref.getImageName()) && image.getImageTag().equals(ref.getImageTag())) { return image; } } throw new KuraException(KuraErrorCode.NOT_FOUND); } private static KuraMessage success() { final KuraPayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_OK); response.setTimestamp(new Date()); return new KuraMessage(response); } private static KuraMessage notFound() { final KuraPayload response = new KuraResponsePayload(KuraResponsePayload.RESPONSE_CODE_NOTFOUND); response.setTimestamp(new Date()); return new KuraMessage(response); } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/ContainerImage.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https:www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import org.eclipse.kura.container.orchestration.ImageInstanceDescriptor; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; public class ContainerImage extends SystemResourceInfo { private String imageName = ""; private String imageTag = ""; private String imageId = ""; private String imageAuthor = ""; private String imageArch = ""; private long imageSize = 0; public ContainerImage(String name, String version) { super(name, version, SystemResourceType.CONTAINER_IMAGE); this.imageName = name; this.imageTag = version; } public ContainerImage(ImageInstanceDescriptor image) { super(image.getImageName(), image.getImageTag(), SystemResourceType.CONTAINER_IMAGE); this.imageName = image.getImageName(); this.imageTag = image.getImageTag(); this.imageId = image.getImageId(); this.imageAuthor = image.getImageAuthor(); this.imageArch = image.getImageArch(); this.imageSize = image.getImageSize(); } public String getImageName() { return imageName; } public void setImageName(String imageName) { this.imageName = imageName; } public String getImageTag() { return imageTag; } public void setImageTag(String imageTag) { this.imageTag = imageTag; } public String getImageId() { return imageId; } public void setImageId(String imageId) { this.imageId = imageId; } public String getImageAuthor() { return imageAuthor; } public void setImageAuthor(String imageAuthor) { this.imageAuthor = imageAuthor; } public String getImageArch() { return imageArch; } public void setImageArch(String imageArch) { this.imageArch = imageArch; } public long getImageSize() { return imageSize; } public void setImageSize(long imageSize) { this.imageSize = imageSize; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/ContainerImages.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.List; public class ContainerImages { private List images; public ContainerImages(List images) { this.images = images; } public List getContainerImages() { return this.images; } public void setContainerImages(List images) { this.images = images; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/DockerContainer.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https:www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.List; import java.util.stream.Collectors; import org.eclipse.kura.container.orchestration.ContainerInstanceDescriptor; import org.eclipse.kura.container.orchestration.ContainerPort; import org.eclipse.kura.container.orchestration.ContainerState; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; public class DockerContainer extends SystemResourceInfo { private String containerName; private String containerImage; private String containerImageTag; private String containerID; private List containerPortsExternal; private List containerPortsInternal; private ContainerState containerState; private Boolean isFrameworkManaged; public DockerContainer(String name, String version) { super(name, version, SystemResourceType.DOCKER); this.containerName = name; } public DockerContainer(ContainerInstanceDescriptor container) { super(container.getContainerName(), container.getContainerImage() + ":" + container.getContainerImageTag(), SystemResourceType.DOCKER); this.containerName = container.getContainerName(); this.containerImage = container.getContainerImage(); this.containerImageTag = container.getContainerImageTag(); this.containerID = container.getContainerId(); this.containerPortsExternal = container.getContainerPorts().stream().map(ContainerPort::getExternalPort) .collect(Collectors.toList()); this.containerPortsInternal = container.getContainerPorts().stream().map(ContainerPort::getInternalPort) .collect(Collectors.toList()); this.containerState = container.getContainerState(); this.isFrameworkManaged = container.isFrameworkManaged(); } public String getContainerName() { return this.containerName; } public void setContainerName(String containerName) { this.containerName = containerName; } public String getContainerImage() { return this.containerImage; } public void setContainerImage(String containerImage) { this.containerImage = containerImage; } public String getContainerImageTag() { return this.containerImageTag; } public void setContainerImageTag(String containerImageTag) { this.containerImageTag = containerImageTag; } public String getContainerId() { return this.containerID; } public void setContainerId(String id) { this.containerID = id; } public List getContainerPortsExternal() { return this.containerPortsExternal; } public List getContainerPortsInternal() { return this.containerPortsInternal; } public ContainerState getContainerState() { return this.containerState; } public String getFrameworkContainerState() { switch (containerState) { case STARTING: return "installed"; case ACTIVE: return "active"; case FAILED: case STOPPING: return "uninstalled"; default: return "unknown"; } } public void setContainerState(ContainerState containerState) { this.containerState = containerState; } public Boolean isFrameworkManaged() { return this.isFrameworkManaged; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/DockerContainers.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.List; public class DockerContainers { private List containers; public DockerContainers(List containers) { this.containers = containers; } public List getDockerContainers() { return this.containers; } public void setDockerContainers(List containers) { this.containers = containers; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundle.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; public class SystemBundle extends SystemResourceInfo { private long id; private String state; private boolean signed; public SystemBundle(String name, String version) { super(name, version, SystemResourceType.BUNDLE); } public long getId() { return this.id; } public void setId(long id) { this.id = id; } public String getState() { return this.state; } public void setState(String state) { this.state = state; } public void setSigned(boolean signed) { this.signed = signed; } public boolean isSigned() { return signed; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundleRef.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.Optional; public class SystemBundleRef { private final String name; private final Optional version; public SystemBundleRef(String name, Optional version) { this.name = name; this.version = version; } public String getName() { return name; } public Optional getVersion() { return version; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemBundles.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; public class SystemBundles { private SystemBundle[] bundles; public SystemBundle[] getBundles() { return this.bundles; } public void setBundles(SystemBundle[] bundles) { this.bundles = bundles; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemDeploymentPackage.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; public class SystemDeploymentPackage extends SystemResourceInfo { private SystemBundle[] bundleInfos; private boolean signed; public SystemDeploymentPackage(String name, String version) { super(name, version, SystemResourceType.DP); } public SystemBundle[] getBundleInfos() { return this.bundleInfos; } public void setBundleInfos(SystemBundle[] bundleInfos) { this.bundleInfos = bundleInfos; } public void setSigned(boolean signed) { this.signed = signed; } public boolean isSigned() { return signed; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemDeploymentPackages.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; public class SystemDeploymentPackages { private SystemDeploymentPackage[] deploymentPackages; public SystemDeploymentPackage[] getDeploymentPackages() { return this.deploymentPackages; } public void setDeploymentPackages(SystemDeploymentPackage[] deploymentPackages) { this.deploymentPackages = deploymentPackages; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemPackage.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; public class SystemPackage extends SystemResourceInfo { public SystemPackage(String name) { super(name); } public SystemPackage(String name, String version, SystemResourceType type) { super(name, version, type); } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemPackages.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.List; public class SystemPackages { private List packages; public SystemPackages(List packages) { this.packages = packages; } public List getSystemPackages() { return this.packages; } public void setSystemPackages(List packages) { this.packages = packages; } } ================================================ FILE: kura/org.eclipse.kura.core.inventory/src/main/java/org/eclipse/kura/core/inventory/resources/SystemResourcesInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.inventory.resources; import java.util.List; import org.eclipse.kura.system.SystemResourceInfo; public class SystemResourcesInfo { private List resources; public SystemResourcesInfo(List resources) { this.resources = resources; } public List getSystemResources() { return this.resources; } public void setSysteResourcesInfo(List resources) { this.resources = resources; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.keystore Bundle-SymbolicName: org.eclipse.kura.core.keystore;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: com.eclipsesource.json;version="0.9.5", org.bouncycastle.asn1;version="1.78.1", org.bouncycastle.asn1.cms;version="1.78.1", org.bouncycastle.asn1.pkcs;version="1.78.1", org.bouncycastle.asn1.x500;version="1.78.1", org.bouncycastle.asn1.x509;version="1.78.1", org.bouncycastle.cert;version="1.78.1", org.bouncycastle.cert.jcajce;version="1.78.1", org.bouncycastle.cms;version="1.78.1", org.bouncycastle.jcajce.provider.asymmetric.dsa;version="1.78.1", org.bouncycastle.jcajce.provider.asymmetric.ec;version="1.78.1", org.bouncycastle.jcajce.provider.asymmetric.rsa;version="1.78.1", org.bouncycastle.jce.provider;version="1.78.1", org.bouncycastle.openssl;version="1.78.1", org.bouncycastle.openssl.bc;version="1.78.1", org.bouncycastle.openssl.jcajce;version="1.78.1", org.bouncycastle.operator;version="1.78.1", org.bouncycastle.operator.jcajce;version="1.78.1", org.bouncycastle.pkcs;version="1.78.1", org.bouncycastle.pkcs.jcajce;version="1.78.1", org.bouncycastle.util;version="1.78.1", org.bouncycastle.util.io.pem;version="1.78.1", org.eclipse.kura;version="[1.6,2.0)", org.eclipse.kura.certificate;version="[2.1,3.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.crypto;version="[1.1,2.0)", org.eclipse.kura.security.keystore;version="[1.2,1.3)", org.eclipse.kura.system;version="[1.5,2.0)", org.eclipse.kura.util.configuration;version="[1.0,2.0)", org.eclipse.kura.util.service;version="[1.0,2.0)", org.osgi.framework;version="1.10.0", org.osgi.service.component;version="1.2.0", org.osgi.service.event;version="1.4.0", org.osgi.service.useradmin;version="1.1.0", org.osgi.util.tracker;version="1.5.2", org.slf4j;version="1.7.32" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.kura.core.keystore.util;version="1.1.0" Eclipse-BuddyPolicy: ext ================================================ FILE: kura/org.eclipse.kura.core.keystore/OSGI-INF/metatype/org.eclipse.kura.core.keystore.FilesystemKeystoreServiceImpl.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.keystore/OSGI-INF/metatype/org.eclipse.kura.core.keystore.PKCS11KeystoreServiceImpl.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.keystore/OSGI-INF/org.eclipse.kura.core.keystore.keystoreService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.keystore/OSGI-INF/org.eclipse.kura.core.keystore.pkcs11KeystoreService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.keystore/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.keystore/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.keystore/build.properties ================================================ # # Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about_files/,\ about.html additional.bundles = org.eclipse.osgi,\ org.eclipse.osgi.util,\ org.eclipse.kura.api src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.keystore/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.keystore 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/BaseKeystoreService.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import static java.util.Objects.isNull; import java.io.File; import java.io.IOException; import java.io.StringWriter; import java.math.BigInteger; import java.net.URI; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.KeyStore.Entry; import java.security.KeyStore.PasswordProtection; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStore.ProtectionParameter; import java.security.KeyStore.SecretKeyEntry; import java.security.KeyStore.TrustedCertificateEntry; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.cert.CRL; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.security.spec.AlgorithmParameterSpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.util.io.pem.PemObject; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.core.keystore.crl.CRLManager; import org.eclipse.kura.core.keystore.crl.CRLManager.CRLVerifier; import org.eclipse.kura.core.keystore.crl.CRLManagerOptions; import org.eclipse.kura.core.keystore.crl.StoredCRL; import org.eclipse.kura.security.keystore.KeystoreChangedEvent; import org.eclipse.kura.security.keystore.KeystoreService; import org.osgi.service.component.ComponentContext; import org.osgi.service.event.EventAdmin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class BaseKeystoreService implements KeystoreService, ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(BaseKeystoreService.class); protected static final String NULL_INPUT_PARAMS_MESSAGE = "Input parameters cannot be null!"; protected static final String KURA_SERVICE_PID = "kura.service.pid"; protected static final String PEM_CERTIFICATE_REQUEST_TYPE = "CERTIFICATE REQUEST"; protected EventAdmin eventAdmin; protected Optional crlManager = Optional.empty(); protected String ownPid; protected ComponentContext componentContext; private CRLManagerOptions crlManagerOptions; static { Security.addProvider(new BouncyCastleProvider()); } public void setEventAdmin(EventAdmin eventAdmin) { this.eventAdmin = eventAdmin; } protected abstract KeystoreInstance loadKeystore() throws KuraException; protected abstract void saveKeystore(KeystoreInstance keystore) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException; protected abstract String getCrlStorePath(); @Override public KeyStore getKeyStore() throws KuraException { return loadKeystore().getKeystore(); } public void activate(ComponentContext context, Map properties) { this.componentContext = context; this.ownPid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); this.crlManagerOptions = new CRLManagerOptions(properties); updateCRLManager(this.crlManagerOptions); } public void updated(Map properties) { logger.info("Bundle {} is updating!", properties.get(KURA_SERVICE_PID)); final CRLManagerOptions newCRLManagerOptions = new CRLManagerOptions(properties); if (!this.crlManagerOptions.equals(newCRLManagerOptions)) { this.crlManagerOptions = newCRLManagerOptions; updateCRLManager(newCRLManagerOptions); } } public void deactivate() { shutdownCRLManager(); } @Override public Entry getEntry(String alias) throws KuraException { if (isNull(alias)) { throw new IllegalArgumentException("Key Pair alias cannot be null!"); } KeystoreInstance ks = loadKeystore(); try { if (ks.getKeystore().entryInstanceOf(alias, PrivateKeyEntry.class) || ks.getKeystore().entryInstanceOf(alias, SecretKeyEntry.class)) { return ks.getKeystore().getEntry(alias, new PasswordProtection(ks.getPassword())); } else { return ks.getKeystore().getEntry(alias, null); } } catch (GeneralSecurityException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get the entry " + alias); } } @Override public void setEntry(String alias, Entry entry) throws KuraException { if (isNull(alias) || alias.trim().isEmpty() || isNull(entry)) { throw new IllegalArgumentException("Input cannot be null or empty!"); } KeystoreInstance ks = loadKeystore(); final ProtectionParameter protectionParameter; if (entry instanceof TrustedCertificateEntry) { protectionParameter = null; } else { protectionParameter = new PasswordProtection(ks.getPassword()); } try { ks.getKeystore().setEntry(alias, entry, protectionParameter); saveKeystore(ks); tryAddToCrlManagement(entry); postChangedEvent(); } catch (GeneralSecurityException | IOException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to set the entry " + alias); } } @Override public Map getEntries() throws KuraException { Map result = new HashMap<>(); KeyStore ks = getKeyStore(); try { List aliases = Collections.list(ks.aliases()); for (String alias : aliases) { Entry tempEntry = getEntry(alias); result.put(alias, tempEntry); } return result; } catch (GeneralSecurityException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get the entries"); } } @Override public void deleteEntry(String alias) throws KuraException { if (isNull(alias)) { throw new IllegalArgumentException("Alias cannot be null!"); } final Optional currentEntry = Optional.ofNullable(getEntry(alias)); if (!currentEntry.isPresent()) { return; } KeystoreInstance ks = loadKeystore(); try { ks.getKeystore().deleteEntry(alias); saveKeystore(ks); tryRemoveFromCrlManagement(currentEntry.get()); postChangedEvent(); } catch (GeneralSecurityException | IOException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to delete entry " + alias); } } @Override public List getKeyManagers(String algorithm) throws KuraException { if (isNull(algorithm)) { throw new IllegalArgumentException("Algorithm cannot be null!"); } KeystoreInstance ks = loadKeystore(); try { KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(ks.getKeystore(), ks.getPassword()); return Arrays.asList(kmf.getKeyManagers()); } catch (GeneralSecurityException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get the key managers for algorithm " + algorithm); } } @Override public List getKeyManagers(String algorithm, String provider) throws KuraException { if (isNull(algorithm)) { throw new IllegalArgumentException("Algorithm cannot be null!"); } if (isNull(provider)) { throw new IllegalArgumentException("Provider cannot be null!"); } KeystoreInstance ks = loadKeystore(); try { KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm, provider); kmf.init(ks.getKeystore(), ks.getPassword()); return Arrays.asList(kmf.getKeyManagers()); } catch (GeneralSecurityException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get the key managers for algorithm " + algorithm + " and provider " + provider); } } @Override public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes) throws KuraException { createKeyPair(alias, algorithm, keySize, signatureAlgorithm, attributes, new SecureRandom()); } @Override public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException { if (isNull(algorithm) || algorithm.trim().isEmpty() || isNull(secureRandom) || isNull(alias) || isNull(attributes) || attributes.trim().isEmpty() || isNull(signatureAlgorithm) || signatureAlgorithm.trim().isEmpty()) { throw new IllegalArgumentException("Parameters cannot be null or empty!"); } KeyPair keyPair; try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, "BC"); keyGen.initialize(keySize, secureRandom); keyPair = keyGen.generateKeyPair(); setEntry(alias, new PrivateKeyEntry(keyPair.getPrivate(), generateCertificateChain(keyPair, signatureAlgorithm, attributes))); } catch (GeneralSecurityException | OperatorCreationException e) { logger.error("Error occured. Exception: {}.", e.getClass()); throw new KuraException(KuraErrorCode.BAD_REQUEST); } } @Override public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException { if (isNull(algorithm) || algorithm.trim().isEmpty() || isNull(secureRandom) || isNull(alias) || isNull(attributes) || attributes.trim().isEmpty() || isNull(signatureAlgorithm) || signatureAlgorithm.trim().isEmpty() || isNull(algorithmParameter)) { throw new IllegalArgumentException("Parameters cannot be null or empty!"); } KeyPair keyPair; try { KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm, "BC"); keyGen.initialize(algorithmParameter, secureRandom); keyPair = keyGen.generateKeyPair(); setEntry(alias, new PrivateKeyEntry(keyPair.getPrivate(), generateCertificateChain(keyPair, signatureAlgorithm, attributes))); } catch (GeneralSecurityException | OperatorCreationException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST); } } @Override public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes) throws KuraException { createKeyPair(alias, algorithm, algorithmParameter, signatureAlgorithm, attributes, new SecureRandom()); } @Override public String getCSR(KeyPair keypair, X500Principal principal, String signerAlg) throws KuraException { if (isNull(principal) || isNull(keypair) || isNull(signerAlg) || signerAlg.trim().isEmpty()) { throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE); } try (StringWriter str = new StringWriter(); JcaPEMWriter pemWriter = new JcaPEMWriter(str);) { ContentSigner signer = new JcaContentSignerBuilder(signerAlg).build(keypair.getPrivate()); PKCS10CertificationRequest csr = getCSRAsPKCS10Builder(keypair, principal).build(signer); PemObject pemCSR = new PemObject(PEM_CERTIFICATE_REQUEST_TYPE, csr.getEncoded()); pemWriter.writeObject(pemCSR); pemWriter.flush(); return str.toString(); } catch (IOException e) { throw new KuraException(KuraErrorCode.ENCODE_ERROR, e, "Failed to get CSR"); } catch (OperatorCreationException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get CSR"); } } @Override public String getCSR(String alias, X500Principal principal, String signerAlg) throws KuraException { if (isNull(principal) || isNull(alias) || alias.trim().isEmpty() || isNull(signerAlg) || signerAlg.trim().isEmpty()) { throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE); } Entry entry = getEntry(alias); if (entry == null) { throw new KuraException(KuraErrorCode.NOT_FOUND); } if (!(entry instanceof PrivateKeyEntry)) { throw new KuraException(KuraErrorCode.BAD_REQUEST); } PrivateKey privateKey = ((PrivateKeyEntry) entry).getPrivateKey(); PublicKey publicKey = ((PrivateKeyEntry) entry).getCertificate().getPublicKey(); KeyPair keyPair = new KeyPair(publicKey, privateKey); return getCSR(keyPair, principal, signerAlg); } protected PKCS10CertificationRequestBuilder getCSRAsPKCS10Builder(KeyPair keyPair, X500Principal principal) { if (isNull(principal) || isNull(keyPair)) { throw new IllegalArgumentException(NULL_INPUT_PARAMS_MESSAGE); } return new JcaPKCS10CertificationRequestBuilder(principal, keyPair.getPublic()); } @Override public List getAliases() throws KuraException { KeyStore ks = getKeyStore(); try { return Collections.list(ks.aliases()); } catch (GeneralSecurityException e) { throw new KuraException(KuraErrorCode.BAD_REQUEST, e, "Failed to get aliases"); } } @Override public Collection getCRLs() { final Optional currentCRLManager = this.crlManager; if (!currentCRLManager.isPresent()) { return Collections.emptyList(); } else { return new ArrayList<>(currentCRLManager.get().getCrls()); } } @Override public CertStore getCRLStore() throws KuraException { final Optional currentCRLManager = this.crlManager; try { if (!currentCRLManager.isPresent()) { return CertStore.getInstance("Collection", new CollectionCertStoreParameters()); } else { return currentCRLManager.get().getCertStore(); } } catch (final Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, e); } } @Override public void addCRL(X509CRL crl) throws KuraException { this.crlManager.ifPresent(manager -> { StoredCRL storedCRL = new StoredCRL(Collections.emptySet(), crl); manager.getCRLStore().storeCRL(storedCRL); }); } protected void postChangedEvent() { this.eventAdmin.postEvent(new KeystoreChangedEvent(ownPid)); } protected X509Certificate[] generateCertificateChain(KeyPair keyPair, String signatureAlgorithm, String attributes) throws OperatorCreationException, CertificateException { Provider bcProvider = new BouncyCastleProvider(); Security.addProvider(bcProvider); long now = System.currentTimeMillis(); Date startDate = new Date(now); X500Name dnName = new X500Name(attributes); // Use the timestamp as serial number BigInteger certSerialNumber = new BigInteger(Long.toString(now)); Calendar calendar = Calendar.getInstance(); calendar.setTime(startDate); calendar.add(Calendar.YEAR, 1); Date endDate = calendar.getTime(); SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, subjectPublicKeyInfo); ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(bcProvider) .build(keyPair.getPrivate()); X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner); return new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(certificateHolder) }; } protected Optional extractCertificate(final Entry entry) { if (!(entry instanceof TrustedCertificateEntry)) { return Optional.empty(); } final TrustedCertificateEntry trustedCertificateEntry = (TrustedCertificateEntry) entry; final Certificate certificate = trustedCertificateEntry.getTrustedCertificate(); if (!(certificate instanceof X509Certificate)) { return Optional.empty(); } else { return Optional.of((X509Certificate) certificate); } } protected boolean tryAddToCrlManagement(final Entry entry) { final Optional certificate = extractCertificate(entry); final Optional currentCrlManager = this.crlManager; if (certificate.isPresent() && currentCrlManager.isPresent()) { return currentCrlManager.get().addTrustedCertificate(certificate.get()); } else { return false; } } protected boolean tryRemoveFromCrlManagement(final Entry entry) { final Optional certificate = extractCertificate(entry); final Optional currentCrlManager = this.crlManager; if (certificate.isPresent() && currentCrlManager.isPresent()) { return currentCrlManager.get().removeTrustedCertificate(certificate.get()); } else { return false; } } protected void updateCRLManager(final CRLManagerOptions newCRLManagerOptions) { shutdownCRLManager(); if (this.crlManagerOptions.isCrlManagementEnabled()) { final CRLManager currentCRLManager = new CRLManager( this.crlManagerOptions.getStoreFile().orElseGet(() -> new File(getCrlStorePath())), 5000, newCRLManagerOptions.getCrlCheckIntervalMs(), newCRLManagerOptions.getCrlUpdateIntervalMs(), getCRLVerifier(newCRLManagerOptions)); currentCRLManager.setListener(Optional.of(this::postChangedEvent)); for (final URI uri : newCRLManagerOptions.getCrlURIs()) { currentCRLManager.addDistributionPoint(Collections.singleton(uri)); } try { for (final Entry e : getEntries().values()) { if (!(e instanceof TrustedCertificateEntry)) { continue; } final TrustedCertificateEntry certEntry = (TrustedCertificateEntry) e; final Certificate cert = certEntry.getTrustedCertificate(); if (cert instanceof X509Certificate) { currentCRLManager.addTrustedCertificate((X509Certificate) cert); } } } catch (final Exception e) { logger.warn("failed to add current trusted certificates to CRL manager", e); } this.crlManager = Optional.of(currentCRLManager); } } protected CRLVerifier getCRLVerifier(final CRLManagerOptions options) { if (!options.isCRLVerificationEnabled()) { return crl -> true; } return crl -> { try { for (final Entry e : getEntries().values()) { if (!(e instanceof TrustedCertificateEntry)) { continue; } final TrustedCertificateEntry trustedCertEntry = (TrustedCertificateEntry) e; if (verifyCRL(crl, trustedCertEntry)) { return true; } } return false; } catch (final Exception e) { logger.warn("Exception verifying CRL", e); return false; } }; } protected void shutdownCRLManager() { if (this.crlManager.isPresent()) { this.crlManager.get().close(); this.crlManager = Optional.empty(); } } protected boolean verifyCRL(X509CRL crl, final TrustedCertificateEntry trustedCertEntry) { try { crl.verify(trustedCertEntry.getTrustedCertificate().getPublicKey()); return true; } catch (final Exception e) { return false; } } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import static org.eclipse.kura.core.keystore.FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PASSWORD; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.security.KeyStore; import java.security.KeyStore.Entry; import java.security.KeyStore.PasswordProtection; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.UnrecoverableEntryException; import java.security.cert.CertificateException; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraRuntimeException; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.crypto.CryptoService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FilesystemKeystoreServiceImpl extends BaseKeystoreService { private static final Logger logger = LoggerFactory.getLogger(FilesystemKeystoreServiceImpl.class); private CryptoService cryptoService; private ConfigurationService configurationService; private FilesystemKeystoreServiceOptions keystoreServiceOptions; private ScheduledExecutorService selfUpdaterExecutor; private ScheduledFuture selfUpdaterFuture; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void setConfigurationService(ConfigurationService configurationService) { this.configurationService = configurationService; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- @Override public void activate(ComponentContext context, Map properties) { logger.info("Bundle {} is starting!", properties.get(KURA_SERVICE_PID)); this.componentContext = context; this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(properties, this.cryptoService); this.selfUpdaterExecutor = Executors.newSingleThreadScheduledExecutor(); if (!keystoreExists(this.keystoreServiceOptions.getKeystorePath())) { try { createKeystore(this.keystoreServiceOptions); } catch (Exception e) { logger.error("Keystore file creation failed", e); } } if (this.keystoreServiceOptions.needsRandomPassword()) { setRandomPassword(); } super.activate(context, properties); logger.info("Bundle {} has started!", properties.get(KURA_SERVICE_PID)); } @Override public void updated(Map properties) { logger.info("Bundle {} is updating!", properties.get(KURA_SERVICE_PID)); FilesystemKeystoreServiceOptions newOptions = new FilesystemKeystoreServiceOptions(properties, this.cryptoService); if (!this.keystoreServiceOptions.equals(newOptions)) { logger.info("Perform update..."); if (!this.keystoreServiceOptions.getKeystorePath().equals(newOptions.getKeystorePath())) { updateKeystorePath(newOptions); } else { checkAndUpdateKeystorePassword(newOptions); } this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(properties, this.cryptoService); } super.updated(properties); logger.info("Bundle {} has updated!", properties.get(KURA_SERVICE_PID)); } @Override public void deactivate() { logger.info("Bundle {} is deactivating!", this.keystoreServiceOptions.getProperties().get(KURA_SERVICE_PID)); if (this.selfUpdaterFuture != null && !this.selfUpdaterFuture.isDone()) { logger.info("Self updater task running. Stopping it"); this.selfUpdaterFuture.cancel(true); } super.deactivate(); } @Override protected void saveKeystore(KeystoreInstance ks) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { try (FileOutputStream tsOutStream = new FileOutputStream(this.keystoreServiceOptions.getKeystorePath());) { ks.getKeystore().store(tsOutStream, ks.getPassword()); } } @Override protected KeystoreInstance loadKeystore() throws KuraException { return loadKeystore(this.keystoreServiceOptions); } @Override protected String getCrlStorePath() { return this.keystoreServiceOptions.getKeystorePath() + ".crl"; } private void checkAndUpdateKeystorePassword(final FilesystemKeystoreServiceOptions options) { try { final KeystoreInstance ks = loadKeystore(this.keystoreServiceOptions); final char[] configPassword = options.getKeystorePassword(cryptoService); if (!Arrays.equals(ks.getPassword(), configPassword)) { setKeystorePassword(ks, configPassword); } } catch (final Exception e) { logger.warn("failed to load or update keystore password", e); } } private boolean keystoreExists(String keystorePath) { return keystorePath != null && new File(keystorePath).isFile(); } private void createKeystore(FilesystemKeystoreServiceOptions options) throws Exception { String keystorePath = options.getKeystorePath(); char[] passwordChar = options.getKeystorePassword(this.cryptoService); if (keystorePath == null) { return; } File fKeyStore = new File(keystorePath); if (!fKeyStore.createNewFile()) { logger.error("Keystore file already exists at location {}", keystorePath); throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, "keystore.path", keystorePath, "file already exists"); } // Immediately save the keystore with the default password to allow to be loaded with the default password. try (OutputStream os = new FileOutputStream(fKeyStore)) { KeyStore newKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); newKeystore.load(null, passwordChar); newKeystore.store(os, passwordChar); os.flush(); } catch (Exception e) { logger.error("Unable to load and store the keystore", e); throw e; } setKeystorePassword(this.loadKeystore(options), passwordChar); } private void updateKeystorePath(FilesystemKeystoreServiceOptions newOptions) { if (!keystoreExists(newOptions.getKeystorePath())) { try { createKeystore(newOptions); } catch (Exception e) { logger.error("Keystore file creation failed", e); } } try { loadKeystore(newOptions); } catch (final Exception e) { logger.warn("Keystore {} not accessible!", newOptions.getKeystorePath()); } } private void setRandomPassword() { try { final KeystoreInstance keystore = loadKeystore(this.keystoreServiceOptions); char[] newPassword = new BigInteger(160, new SecureRandom()).toString(32).toCharArray(); setKeystorePassword(keystore, newPassword); Map props = new HashMap<>(this.keystoreServiceOptions.getProperties()); props.put(KEY_KEYSTORE_PASSWORD, new String(this.cryptoService.encryptAes(newPassword))); this.keystoreServiceOptions = new FilesystemKeystoreServiceOptions(props, this.cryptoService); updatePasswordInConfigService(newPassword); } catch (Exception e) { logger.warn("Keystore password change failed", e); } } private synchronized void saveKeystore(KeystoreInstance ks, char[] keyStorePassword) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { try (FileOutputStream tsOutStream = new FileOutputStream(((KeystoreInstanceImpl) ks).path)) { ks.getKeystore().store(tsOutStream, keyStorePassword); } } private void updatePasswordInConfigService(char[] newPassword) { final String pid = this.keystoreServiceOptions.getPid(); Map props = new HashMap<>(); props.putAll(this.keystoreServiceOptions.getProperties()); props.put(FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PATH, this.keystoreServiceOptions.getKeystorePath()); props.put(FilesystemKeystoreServiceOptions.KEY_KEYSTORE_PASSWORD, new Password(newPassword)); props.put(FilesystemKeystoreServiceOptions.KEY_RANDOMIZE_PASSWORD, false); this.selfUpdaterFuture = this.selfUpdaterExecutor.scheduleAtFixedRate(() -> { try { if (this.componentContext.getServiceReference() != null && this.configurationService.getComponentConfiguration(pid) != null && this.configurationService.getComponentConfiguration(pid).getDefinition() != null) { this.configurationService.updateConfiguration(pid, props); throw new KuraRuntimeException(KuraErrorCode.CONFIGURATION_SNAPSHOT_TAKING, "Updated. The task will be terminated."); } else { logger.info("No service or configuration available yet."); } } catch (KuraException e) { logger.warn("Cannot get/update configuration for pid: {}", pid, e); } }, 1000, 1000, TimeUnit.MILLISECONDS); } private synchronized void setKeystorePassword(KeystoreInstance ks, char[] password) { try { updateKeyEntriesPasswords(ks, password); saveKeystore(ks, password); this.cryptoService.setKeyStorePassword(((KeystoreInstanceImpl) ks).path, password); } catch (NoSuchAlgorithmException | CertificateException | KeyStoreException | UnrecoverableEntryException | IOException e) { logger.warn("Failed to change keystore password"); } catch (KuraException e) { logger.warn("Failed to persist keystore password"); } } private static void updateKeyEntriesPasswords(KeystoreInstance ks, char[] newPassword) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException { Enumeration aliases = ks.getKeystore().aliases(); while (aliases.hasMoreElements()) { String alias = aliases.nextElement(); if (ks.getKeystore().isKeyEntry(alias)) { PasswordProtection oldPP = new PasswordProtection(ks.getPassword()); Entry entry = ks.getKeystore().getEntry(alias, oldPP); PasswordProtection newPP = new PasswordProtection(newPassword); ks.getKeystore().setEntry(alias, entry, newPP); } } } private synchronized KeystoreInstance loadKeystore(final FilesystemKeystoreServiceOptions options) throws KuraException { final List passwords = new ArrayList<>(2); passwords.add(options.getKeystorePassword(cryptoService)); char[] passwordInCrypto = null; try { passwordInCrypto = this.cryptoService.getKeyStorePassword(options.getKeystorePath()); if (passwordInCrypto != null) { passwords.add(passwordInCrypto); } } catch (final Exception e) { logger.debug("failed to retrieve password", e); } final KeystoreInstance result = new KeystoreLoader(options.getKeystorePath(), passwords).loadKeystore(); if (!Arrays.equals(passwordInCrypto, result.getPassword())) { this.cryptoService.setKeyStorePassword(((KeystoreInstanceImpl) result).path, result.getPassword()); } return result; } private static class KeystoreLoader { private final String path; private final List passwords; KeystoreLoader(final String path, final List passwords) { this.path = path; this.passwords = passwords; } private KeyStore loadKeystore(final String path, final char[] password) throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException { return KeyStore.getInstance(new File(path), password); } KeystoreInstance loadKeystore() throws KuraException { for (final char[] password : this.passwords) { try { final KeyStore keyStore = loadKeystore(path, password); return new KeystoreInstanceImpl(keyStore, password, this.path); } catch (final Exception e) { logger.debug("failed to load keystore", e); } } throw new KuraException(KuraErrorCode.BAD_REQUEST, "Failed to get the KeyStore"); } } private static class KeystoreInstanceImpl implements KeystoreInstance { private final KeyStore keystore; private final char[] password; private final String path; public KeystoreInstanceImpl(final KeyStore keystore, final char[] password, final String path) { this.keystore = keystore; this.password = password; this.path = path; } @Override public KeyStore getKeystore() { return keystore; } @Override public char[] getPassword() { return password; } } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/FilesystemKeystoreServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import static java.util.Objects.isNull; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.util.Arrays; import java.util.Map; import java.util.Objects; import org.eclipse.kura.configuration.Password; import org.eclipse.kura.crypto.CryptoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FilesystemKeystoreServiceOptions { private static final Logger logger = LoggerFactory.getLogger(FilesystemKeystoreServiceOptions.class); private static final String KEY_SERVICE_PID = "kura.service.pid"; static final String KEY_KEYSTORE_PATH = "keystore.path"; static final String KEY_KEYSTORE_PASSWORD = "keystore.password"; static final String KEY_RANDOMIZE_PASSWORD = "randomize.password"; private static final String DEFAULT_KEYSTORE_PATH = "/tmp/keystore.ks"; private static final boolean DEFAULT_RANDOMIZE_PASSWORD = false; static final String DEFAULT_KEYSTORE_PASSWORD = "changeit"; private final Map properties; private final String pid; private final String keystorePath; private final Password keystorePassword; private final boolean randomPassword; public FilesystemKeystoreServiceOptions(Map properties, final CryptoService cryptoService) { if (isNull(properties) || isNull(cryptoService)) { throw new IllegalArgumentException("Input parameters cannot be null!"); } this.properties = properties; this.pid = (String) properties.get(KEY_SERVICE_PID); String keyStorePath = (String) properties.getOrDefault(KEY_KEYSTORE_PATH, DEFAULT_KEYSTORE_PATH); try { this.keystorePath = validateAndNormalize(keyStorePath); } catch (Exception e) { logger.error("Keystore path {} not valid", keyStorePath); throw new IllegalArgumentException("Invalid keystore path"); } this.keystorePassword = extractPassword(properties, cryptoService); this.randomPassword = (boolean) properties.getOrDefault(KEY_RANDOMIZE_PASSWORD, DEFAULT_RANDOMIZE_PASSWORD); } private String validateAndNormalize(String keystorePath) throws URISyntaxException, InvalidPathException { Paths.get(keystorePath); // throw InvalidPathException if invalid return new URI(keystorePath).normalize().toString(); } private static Password extractPassword(final Map properties, final CryptoService cryptoService) { final Object optionsPassword = properties.get(KEY_KEYSTORE_PASSWORD); if (optionsPassword instanceof String) { return new Password((String) optionsPassword); } try { return new Password(cryptoService.encryptAes(DEFAULT_KEYSTORE_PASSWORD.toCharArray())); } catch (final Exception e) { logger.warn("failed to encrypt default keystore password", e); return new Password(DEFAULT_KEYSTORE_PASSWORD); } } public Map getProperties() { return this.properties; } public String getPid() { return this.pid; } public String getKeystorePath() { return this.keystorePath; } public char[] getKeystorePassword(final CryptoService cryptoService) { try { return cryptoService.decryptAes(this.keystorePassword.getPassword()); } catch (final Exception e) { return this.keystorePassword.getPassword(); } } public boolean needsRandomPassword() { return this.randomPassword; } @Override public int hashCode() { return Objects.hash(Arrays.hashCode(keystorePassword.getPassword()), keystorePath, pid, randomPassword); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } FilesystemKeystoreServiceOptions other = (FilesystemKeystoreServiceOptions) obj; return Arrays.equals(keystorePassword.getPassword(), other.keystorePassword.getPassword()) && Objects.equals(keystorePath, other.keystorePath) && Objects.equals(pid, other.pid) && randomPassword == other.randomPassword; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/KeystoreInstance.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import java.security.KeyStore; public interface KeystoreInstance { public KeyStore getKeystore(); public char[] getPassword(); } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/PKCS11KeystoreServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.file.Files; import java.security.KeyStore; import java.security.KeyStore.Entry; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; import java.security.Security; import java.security.cert.CertificateException; import java.security.spec.AlgorithmParameterSpec; import java.util.Map; import java.util.Optional; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.system.SystemService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class PKCS11KeystoreServiceImpl extends BaseKeystoreService { private static final Logger logger = LoggerFactory.getLogger(PKCS11KeystoreServiceImpl.class); Optional provider = Optional.empty(); private PKCS11KeystoreServiceOptions options; private CryptoService cryptoService; private SystemService systemService; public void setCryptoService(final CryptoService cryptoService) { this.cryptoService = cryptoService; } public void setSystemService(final SystemService systemService) { this.systemService = systemService; } @Override public void activate(ComponentContext context, Map properties) { super.activate(context, properties); options = new PKCS11KeystoreServiceOptions(properties, ownPid); } @Override public void updated(Map properties) { super.updated(properties); PKCS11KeystoreServiceOptions newOptions = new PKCS11KeystoreServiceOptions(properties, ownPid); if (!newOptions.equals(this.options)) { logger.info("Options changed..."); removeProvider(); this.options = newOptions; } } @Override public void deactivate() { removeProvider(); super.deactivate(); } @Override protected KeystoreInstance loadKeystore() throws KuraException { final Provider currentProvider = getOrRegisterProvider(); try { final KeyStore store = KeyStore.getInstance("PKCS11", currentProvider); final char[] pin = this.options.getPin(cryptoService).orElse(null); store.load(null, pin); return new KeystoreInstanceImpl(store, pin); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { removeProvider(); logger.warn("Keystore exception", e); throw new KuraException(KuraErrorCode.SECURITY_EXCEPTION); } } @Override protected void saveKeystore(KeystoreInstance keystore) { // no need } @Override public void setEntry(String alias, Entry entry) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override public void deleteEntry(String alias) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override public void createKeyPair(String alias, String algorithm, AlgorithmParameterSpec algorithmParameter, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override public void createKeyPair(String alias, String algorithm, int keySize, String signatureAlgorithm, String attributes, SecureRandom secureRandom) throws KuraException { throw new KuraException(KuraErrorCode.OPERATION_NOT_SUPPORTED); } @Override protected String getCrlStorePath() { return this.options.getCrlStorePath().orElseGet( () -> this.systemService.getKuraUserConfigDirectory() + "/security/pkcs11." + ownPid + ".crl"); } private synchronized Provider getOrRegisterProvider() throws KuraException { if (provider.isPresent()) { return provider.get(); } logger.info("Registering provider..."); final String config = this.options.buildSunPKCS11ProviderConfig() .orElseThrow(() -> new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_UNDEFINED, "library.path")); logger.debug("PKCS11 config: {}", config); final String javaVersion = System.getProperty("java.version"); final Provider newProvider; if (javaVersion.startsWith("1.")) { newProvider = registerProviderJava8(config); } else { newProvider = registerProviderJava9(config); } this.provider = Optional.of(newProvider); logger.info("Registering provider...done"); return newProvider; } private Provider registerProviderJava8(final String config) throws KuraException { try { final Class providerClass = Class.forName("sun.security.pkcs11.SunPKCS11"); final Constructor ctor = providerClass.getConstructor(InputStream.class); final Provider newProvider = (Provider) ctor.newInstance(new ByteArrayInputStream(config.getBytes())); Security.addProvider(newProvider); return newProvider; } catch (final Exception e) { logger.warn("failed to load PKCS11 provider", e); throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE); } } private Provider registerProviderJava9(final String config) throws KuraException { try { Provider newProvider = Security.getProvider("SunPKCS11"); final Method configure = Provider.class.getMethod("configure", String.class); final File configFile = Files.createTempFile(null, null).toFile(); try { try (final OutputStream out = new FileOutputStream(configFile)) { out.write(config.getBytes()); } newProvider = (Provider) configure.invoke(newProvider, configFile.getAbsolutePath()); Security.addProvider(newProvider); return newProvider; } finally { Files.deleteIfExists(configFile.toPath()); } } catch (final Exception e) { logger.warn("failed to load PKCS11 provider", e); throw new KuraException(KuraErrorCode.SERVICE_UNAVAILABLE); } } private synchronized void removeProvider() { if (!provider.isPresent()) { return; } logger.info("Removing provider..."); Security.removeProvider(provider.get().getName()); provider = Optional.empty(); logger.info("Removing provider...done"); } private class KeystoreInstanceImpl implements KeystoreInstance { private final KeyStore keystore; private final char[] password; KeystoreInstanceImpl(KeyStore keystore, char[] password) { this.keystore = keystore; this.password = password; } @Override public KeyStore getKeystore() { return keystore; } @Override public char[] getPassword() { return password; } } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/PKCS11KeystoreServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore; import java.util.Map; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.KuraException; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.util.configuration.Property; public class PKCS11KeystoreServiceOptions { private static final Property PKCS11_LIBRARY_PROPERTY = new Property<>("library.path", String.class); private static final Property PIN_PROPERTY = new Property<>("pin", String.class); private static final Property SLOT_PROPERTY = new Property<>("slot", Integer.class); private static final Property SLOT_LIST_INDEX_PROPERTY = new Property<>("slot.list.index", Integer.class); private static final Property ENABLED_MECHANISMS_PROPERTY = new Property<>("enabled.mechanisms", String.class); private static final Property DISABLED_MECHANISMS_PROPERTY = new Property<>("disabled.mechanisms", String.class); private static final Property ATTRIBUTES_PROPERTY = new Property<>("attributes", String.class); private static final Property CRL_STORE_PATH = new Property<>("crl.store.path", String.class); private final String ownPid; private final Optional libraryPath; private final Optional pin; private final Optional slot; private final Optional slotListIndex; private final Optional enabledMechanisms; private final Optional disabledMechanisms; private final Optional attributes; private final Optional crlStorePath; public PKCS11KeystoreServiceOptions(final Map properties, final String ownPid) { this.libraryPath = PKCS11_LIBRARY_PROPERTY.getOptional(properties); this.pin = PIN_PROPERTY.getOptional(properties); this.ownPid = ownPid; this.slot = SLOT_PROPERTY.getOptional(properties); this.slotListIndex = SLOT_LIST_INDEX_PROPERTY.getOptional(properties); this.enabledMechanisms = ENABLED_MECHANISMS_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty()); this.disabledMechanisms = DISABLED_MECHANISMS_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty()); this.attributes = ATTRIBUTES_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty()); this.crlStorePath = CRL_STORE_PATH.getOptional(properties).filter(s -> !s.trim().isEmpty()); } public Optional getLibraryPath() { return libraryPath; } public Optional getPin(final CryptoService cryptoService) throws KuraException { if (!pin.isPresent()) { return Optional.empty(); } return Optional.of(cryptoService.decryptAes(pin.get().toCharArray())); } public String getOwnPid() { return ownPid; } public Optional getSlot() { return slot; } public Optional getSlotListIndex() { return slotListIndex; } public Optional getEnabledMechanisms() { return enabledMechanisms; } public Optional getDisabledMechanisms() { return disabledMechanisms; } public Optional getAttributes() { return attributes; } public Optional getCrlStorePath() { return crlStorePath; } @Override public int hashCode() { return Objects.hash(attributes, crlStorePath, disabledMechanisms, enabledMechanisms, libraryPath, ownPid, pin, slot, slotListIndex); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof PKCS11KeystoreServiceOptions)) { return false; } PKCS11KeystoreServiceOptions other = (PKCS11KeystoreServiceOptions) obj; return Objects.equals(attributes, other.attributes) && Objects.equals(crlStorePath, other.crlStorePath) && Objects.equals(disabledMechanisms, other.disabledMechanisms) && Objects.equals(enabledMechanisms, other.enabledMechanisms) && Objects.equals(libraryPath, other.libraryPath) && Objects.equals(ownPid, other.ownPid) && Objects.equals(pin, other.pin) && Objects.equals(slot, other.slot) && Objects.equals(slotListIndex, other.slotListIndex); } public Optional buildSunPKCS11ProviderConfig() { if (!this.libraryPath.isPresent()) { return Optional.empty(); } final StringBuilder builder = new StringBuilder(); builder.append("library = ").append(libraryPath.get()).append('\n'); builder.append("name = kura.provider.").append(ownPid).append('\n'); if (slot.isPresent()) { builder.append("slot = ").append(slot.get()).append('\n'); } if (slotListIndex.isPresent()) { builder.append("slotListIndex = ").append(slotListIndex.get()).append('\n'); } if (enabledMechanisms.isPresent()) { builder.append("enabledMechanisms = { ").append(enabledMechanisms.get()).append(" }\n"); } if (disabledMechanisms.isPresent()) { builder.append("disabledMechanisms = { ").append(disabledMechanisms.get()).append(" }\n"); } if (attributes.isPresent()) { builder.append(attributes.get()); } return Optional.of(builder.toString()); } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLManager.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.crl; import java.io.Closeable; import java.io.File; import java.net.URI; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertStore; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.OptionalLong; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import org.eclipse.kura.core.keystore.util.CRLUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CRLManager implements Closeable { private static final Logger logger = LoggerFactory.getLogger(CRLManager.class); private final CRLStore store; private final ScheduledExecutorService updateExecutor = Executors.newSingleThreadScheduledExecutor(); private final ExecutorService downloadExecutor = Executors.newCachedThreadPool(); private final List referencedDistributionPoints = new ArrayList<>(); private final long forceUpdateIntervalNanos; private final long periodicReckeckIntervalMs; private final CRLVerifier verifier; private Optional> updateTask = Optional.empty(); private Optional listener; public CRLManager(final File storeFile, final long storeDelayMs, final long periodicRecheckIntervalMs, final long forceUpdateIntervalMs, final CRLVerifier verifier) { this.store = new CRLStore(storeFile, storeDelayMs); this.periodicReckeckIntervalMs = periodicRecheckIntervalMs; this.forceUpdateIntervalNanos = Duration.ofMillis(forceUpdateIntervalMs).toNanos(); this.verifier = verifier; requestUpdate(); } public void setListener(final Optional listener) { this.listener = listener; } public synchronized boolean addDistributionPoint(final Set uris) { logger.info("referencing distribution points: {}", uris); final Optional existing = this.referencedDistributionPoints.stream() .filter(p -> p.distributionPoints.equals(uris)).findAny(); if (existing.isPresent()) { existing.get().ref(); return false; } else { this.referencedDistributionPoints.add(new DistributionPointState(uris)); requestUpdate(); return true; } } public synchronized boolean removeDistributionPoint(final Set uris) { logger.info("unreferencing distribution points: {}", uris); if (this.referencedDistributionPoints.removeIf(p -> p.distributionPoints.equals(uris) && p.unref() <= 0)) { requestUpdate(); return true; } else { return false; } } public boolean addTrustedCertificate(final X509Certificate entry) { final Set distributionPoints; try { distributionPoints = CRLUtil.getCrlURIs(entry); } catch (final Exception e) { logger.warn("failed to get distribution points for {}", entry.getSubjectX500Principal(), e); return false; } if (distributionPoints.isEmpty()) { logger.info("certificate {} has no CRL distribution points", entry.getSubjectX500Principal()); return false; } return addDistributionPoint(distributionPoints); } public boolean removeTrustedCertificate(final X509Certificate entry) { try { final Set distributionPoints = CRLUtil.getCrlURIs(entry); return removeDistributionPoint(distributionPoints); } catch (final Exception e) { logger.warn("failed to get distribution points for {}", entry.getSubjectX500Principal(), e); return false; } } public synchronized List getCrls() { return this.store.getCRLs().stream().map(StoredCRL::getCrl).collect(Collectors.toList()); } public CertStore getCertStore() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return this.store.getCertStore(); } public CRLStore getCRLStore() { return this.store; } @Override public void close() { this.listener = Optional.empty(); this.updateExecutor.shutdown(); this.downloadExecutor.shutdown(); } private void requestUpdate() { if (this.updateTask.isPresent()) { this.updateTask.get().cancel(false); } this.updateTask = Optional.of(this.updateExecutor.scheduleWithFixedDelay(this::update, 5000, this.periodicReckeckIntervalMs, TimeUnit.MILLISECONDS)); } private synchronized void update() { boolean changed = false; final long now = System.nanoTime(); for (final DistributionPointState state : this.referencedDistributionPoints) { final Optional storedCrl = this.store.getCRLs().stream() .filter(c -> c.getDistributionPoints().equals(state.distributionPoints)).findAny(); if (!storedCrl.isPresent() || storedCrl.get().isExpired() || !state.lastDownloadInstantNanos.isPresent() || now - state.lastDownloadInstantNanos.getAsLong() > this.forceUpdateIntervalNanos) { final CompletableFuture future = CRLUtil.fetchCRL(state.distributionPoints, this.downloadExecutor); try { final X509CRL crl = future.get(1, TimeUnit.MINUTES); changed |= validateAndStoreCRL(now, state, storedCrl, crl); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); logger.warn("failed to download CRL", e); future.cancel(true); } catch (final Exception e) { logger.warn("failed to download CRL", e); future.cancel(true); } } } changed |= this.store.removeCRLs(c -> this.referencedDistributionPoints.stream() .noneMatch(p -> p.distributionPoints.equals(c.getDistributionPoints()))); if (changed) { this.listener.ifPresent(Listener::onCRLCacheChanged); } } private boolean validateAndStoreCRL(final long now, final DistributionPointState state, final Optional storedCrl, final X509CRL newCrl) { if (storedCrl.isPresent()) { final X509CRL stored = storedCrl.get().getCrl(); if (stored.equals(newCrl)) { logger.info("current CRL is up to date"); state.lastDownloadInstantNanos = OptionalLong.of(now); return false; } if (!stored.getIssuerX500Principal().equals(newCrl.getIssuerX500Principal())) { logger.warn("CRL issuer differs, not updating CRL"); return false; } } if (this.verifier.verifyCRL(newCrl)) { this.store.storeCRL(new StoredCRL(state.distributionPoints, newCrl)); state.lastDownloadInstantNanos = OptionalLong.of(now); return true; } else { logger.warn("CRL verification failed"); return false; } } private class DistributionPointState { private int refCnt = 1; private OptionalLong lastDownloadInstantNanos = OptionalLong.empty(); private final Set distributionPoints; public DistributionPointState(Set distributionPoints) { this.distributionPoints = distributionPoints; } int ref() { this.refCnt++; return this.refCnt; } int unref() { this.refCnt--; return this.refCnt; } } public interface CRLVerifier { public boolean verifyCRL(final X509CRL crl); } public interface Listener { public void onCRLCacheChanged(); } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLManagerOptions.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.crl; import java.io.File; import java.net.URI; import java.util.HashSet; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import org.eclipse.kura.util.configuration.Property; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CRLManagerOptions { private static final Logger logger = LoggerFactory.getLogger(CRLManagerOptions.class); private static final Property CRL_MANAGEMENT_ENABLED = new Property<>("crl.management.enabled", false); private static final Property CRL_UPDATE_INTERVAL = new Property<>("crl.update.interval", 1L); private static final Property CRL_UPDATE_INTERVAL_TIME_UNIT = new Property<>( "crl.update.interval.time.unit", TimeUnit.DAYS.name()); private static final Property CRL_CHECK_INTERVAL = new Property<>("crl.check.interval", 5L); private static final Property CRL_CHECK_INTERVAL_TIME_UNIT = new Property<>("crl.check.interval.time.unit", TimeUnit.MINUTES.name()); private static final Property CRL_URLS = new Property<>("crl.urls", new String[0]); private static final Property CRL_STORE_PATH = new Property<>("crl.store.path", String.class); private static final Property CRL_VERIFICATION_ENABLED = new Property<>("verify.crl", true); private final boolean crlManagementEnabled; private final long crlUpdateIntervalMs; private final long crlCheckIntervalMs; private final Set crlURIs; private final Optional crlStore; private final boolean verifyCRL; public CRLManagerOptions(final Map properties) { this.crlManagementEnabled = CRL_MANAGEMENT_ENABLED.get(properties); this.crlUpdateIntervalMs = extractInterval(properties, CRL_UPDATE_INTERVAL, CRL_UPDATE_INTERVAL_TIME_UNIT); this.crlCheckIntervalMs = extractInterval(properties, CRL_CHECK_INTERVAL, CRL_CHECK_INTERVAL_TIME_UNIT); this.crlURIs = extractCrlURIs(properties); this.crlStore = CRL_STORE_PATH.getOptional(properties).filter(s -> !s.trim().isEmpty()).map(File::new); this.verifyCRL = CRL_VERIFICATION_ENABLED.get(properties); } public boolean isCrlManagementEnabled() { return this.crlManagementEnabled; } public long getCrlUpdateIntervalMs() { return this.crlUpdateIntervalMs; } public long getCrlCheckIntervalMs() { return crlCheckIntervalMs; } public Set getCrlURIs() { return this.crlURIs; } public Optional getStoreFile() { return this.crlStore; } public boolean isCRLVerificationEnabled() { return verifyCRL; } private static long extractInterval(final Map properties, final Property valueProperty, final Property timeUnitProperty) { final long updateInterval = valueProperty.get(properties); final TimeUnit timeUnit = TimeUnit.valueOf(timeUnitProperty.get(properties)); return timeUnit.toMillis(updateInterval); } private static Set extractCrlURIs(final Map properties) { final String[] values = CRL_URLS.get(properties); final Set result = new HashSet<>(); for (final String value : values) { if (value == null || value.trim().isEmpty()) { continue; } try { result.add(new URI(value)); } catch (final Exception e) { logger.warn("failed to parse URL: {}", value, e); } } return result; } @Override public int hashCode() { return Objects.hash(crlCheckIntervalMs, crlManagementEnabled, crlStore, crlURIs, crlUpdateIntervalMs, verifyCRL); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof CRLManagerOptions)) { return false; } CRLManagerOptions other = (CRLManagerOptions) obj; return crlCheckIntervalMs == other.crlCheckIntervalMs && crlManagementEnabled == other.crlManagementEnabled && Objects.equals(crlStore, other.crlStore) && Objects.equals(crlURIs, other.crlURIs) && crlUpdateIntervalMs == other.crlUpdateIntervalMs && verifyCRL == other.verifyCRL; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/CRLStore.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.crl; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.Writer; import java.net.URI; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertStore; import java.security.cert.CollectionCertStoreParameters; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.function.Predicate; import org.eclipse.kura.core.keystore.util.MappingCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonValue; public class CRLStore implements Closeable { private static final Logger logger = LoggerFactory.getLogger(CRLStore.class); private final File storeFile; private final Map, StoredCRL> crls = new HashMap<>(); private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); private final long storeDelayMs; private Optional> storeTask = Optional.empty(); public CRLStore(final File storeFile, final long storeDelayMs) { this.storeFile = storeFile; this.storeDelayMs = storeDelayMs; if (storeFile.exists()) { load(); } else { final File parent = storeFile.getParentFile(); if (!parent.isDirectory() && !parent.mkdirs()) { logger.warn("failed to create directory: {}", parent); } } } public synchronized void storeCRL(final StoredCRL crl) { this.crls.put(crl.getDistributionPoints(), crl); requestStore(); } public synchronized boolean removeCRLs(final Predicate predicate) { boolean changed = false; final Iterator iter = this.crls.values().iterator(); while (iter.hasNext()) { final StoredCRL next = iter.next(); if (predicate.test(next)) { logger.info("removing CRL: {}", next.getCrl().getIssuerX500Principal()); changed = true; iter.remove(); } } if (changed) { requestStore(); } return changed; } public Optional getCrl(final Set distributionPoints) { return Optional.ofNullable(this.crls.get(distributionPoints)); } public synchronized List getCRLs() { return new ArrayList<>(crls.values()); } public CertStore getCertStore() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return CertStore.getInstance("Collection", new CollectionCertStoreParameters(new MappingCollection<>(crls.values(), StoredCRL::getCrl))); } private void requestStore() { final Optional> currentTask = this.storeTask; if (currentTask.isPresent()) { currentTask.get().cancel(false); } this.storeTask = Optional.of(this.executor.schedule(this::store, storeDelayMs, TimeUnit.MILLISECONDS)); } private synchronized void load() { try { try (final Reader in = new InputStreamReader(new FileInputStream(this.storeFile))) { final JsonArray array = Json.parse(in).asArray(); for (final JsonValue value : array) { final StoredCRL crl = StoredCRL.fromJson(value.asObject()); logger.info("loaded CRL for {}", crl.getCrl().getIssuerX500Principal()); this.crls.put(crl.getDistributionPoints(), crl); } } } catch (final Exception e) { logger.warn("failed to load CRLs", e); } } private void store() { try { logger.info("storing CRLs..."); final List currentCrls = getCRLs(); final JsonArray array = new JsonArray(); for (final StoredCRL crl : currentCrls) { array.add(crl.toJson()); } final File tmpFile = new File(this.storeFile.getParent(), this.storeFile.getName() + "_"); try (final Writer out = new FileWriter(tmpFile)) { array.writeTo(out); } Files.move(tmpFile.toPath(), this.storeFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); logger.info("storing CRLs...done"); } catch (final Exception e) { logger.warn("failed to store CRLs", e); } } @Override public void close() throws IOException { executor.shutdown(); } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/crl/StoredCRL.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.crl; import java.io.IOException; import java.net.URI; import java.security.cert.CRLException; import java.security.cert.X509CRL; import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder; import java.util.Date; import java.util.HashSet; import java.util.Set; import org.bouncycastle.cert.X509CRLHolder; import org.bouncycastle.cert.jcajce.JcaX509CRLConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonValue; public class StoredCRL { private static final Logger logger = LoggerFactory.getLogger(StoredCRL.class); private static final String DISTRIBUTION_POINTS_KEY = "dps"; private static final String BODY_KEY = "body"; private final Set distributionPoints; private final X509CRL crl; public StoredCRL(final Set distributionPoints, final X509CRL crl) { this.distributionPoints = distributionPoints; this.crl = crl; } public Set getDistributionPoints() { return distributionPoints; } public X509CRL getCrl() { return crl; } public boolean isExpired() { final long now = System.currentTimeMillis(); final Date nextUpdate = crl.getNextUpdate(); return nextUpdate != null && nextUpdate.getTime() < now; } public static StoredCRL fromJson(final JsonObject object) throws IOException, CRLException { final Set dps = new HashSet<>(); final JsonArray dpsArray = object.get(DISTRIBUTION_POINTS_KEY).asArray(); for (final JsonValue value : dpsArray) { try { dps.add(new URI(value.asString())); } catch (final Exception e) { logger.warn("failed to parse URI", e); } } final String body = object.get(BODY_KEY).asString(); final Decoder decoder = Base64.getDecoder(); final byte[] decoded = decoder.decode(body); final X509CRLHolder holder = new X509CRLHolder(decoded); return new StoredCRL(dps, new JcaX509CRLConverter().getCRL(holder)); } public JsonObject toJson() throws CRLException { final JsonObject result = new JsonObject(); final JsonArray dpsArray = new JsonArray(); for (final URI uri : this.distributionPoints) { dpsArray.add(uri.toString()); } result.add(DISTRIBUTION_POINTS_KEY, dpsArray); final Encoder encoder = Base64.getEncoder(); final String body = encoder.encodeToString(crl.getEncoded()); result.add(BODY_KEY, body); return result; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CRLUtil.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.util; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URI; import java.net.URLConnection; import java.security.cert.CertificateFactory; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import org.bouncycastle.asn1.ASN1IA5String; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.bouncycastle.asn1.x509.DistributionPoint; import org.bouncycastle.asn1.x509.DistributionPointName; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CRLUtil { private static final Logger logger = LoggerFactory.getLogger(CRLUtil.class); private CRLUtil() { } public static Set getCrlURIs(final X509Certificate cert) throws IOException { final byte[] crlDistributionPoints = cert.getExtensionValue(Extension.cRLDistributionPoints.getId()); if (crlDistributionPoints == null) { return Collections.emptySet(); } try (final ASN1InputStream in0 = new ASN1InputStream(crlDistributionPoints); final ASN1InputStream in = new ASN1InputStream(((DEROctetString) in0.readObject()).getOctets())) { final DistributionPoint[] distributionPoints = CRLDistPoint.getInstance(in.readObject()) .getDistributionPoints(); if (distributionPoints == null) { return Collections.emptySet(); } final Set result = new HashSet<>(); for (final DistributionPoint distributionPoint : distributionPoints) { final DistributionPointName distributionPointName = distributionPoint.getDistributionPoint(); if (distributionPointName == null || distributionPointName.getType() != DistributionPointName.FULL_NAME) { logger.warn("failed to get distribution point name"); continue; } final GeneralName[] generalNames = GeneralNames.getInstance(distributionPointName.getName()).getNames(); for (final GeneralName name : generalNames) { if (name.getTagNo() == GeneralName.uniformResourceIdentifier) { final String uriString = ASN1IA5String.getInstance(name.getName()).getString(); parseURI(uriString).ifPresent(result::add); } } } return result; } } public static CompletableFuture fetchCRL(final Set uris, final ExecutorService executor) { final CompletableFuture result = new CompletableFuture<>(); executor.execute(() -> { for (final URI uri : uris) { logger.info("fetching CRL from: {}...", uri); try (final InputStream in = openConnection(uri)) { final CertificateFactory cf = CertificateFactory.getInstance("X.509"); final X509CRL crl = (X509CRL) cf.generateCRL(in); logger.info("fetching CRL from: {}...done", uri); result.complete(crl); return; } catch (final Exception e) { logger.warn("failed to fetch CRL from {}", uri, e); } if (Thread.interrupted()) { logger.warn("interrupted"); result.completeExceptionally(new InterruptedException()); return; } } result.completeExceptionally(new IOException("failed to download CRL from: " + uris)); }); return result; } private static InputStream openConnection(final URI uri) throws IOException { final URLConnection connection = uri.toURL().openConnection(); if (connection instanceof HttpURLConnection) { ((HttpURLConnection) connection).setRequestProperty("Accept", "*/*"); ((HttpURLConnection) connection).setRequestProperty("Connection", "Close"); } return connection.getInputStream(); } private static Optional parseURI(final String value) { try { return Optional.of(new URI(value)); } catch (final Exception e) { logger.warn("failed to parse distribution point URL", e); return Optional.empty(); } } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CertificateInfo.java ================================================ /******************************************************************************* * Copyright (c) 2020, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; import java.util.Collection; import java.util.List; /** * Identifies a certificate with its alias and the corresponding keystore name. * Further certificate information can be added (i.e. subjectDN, issuer, ecc.) * * @since 2.2 */ public class CertificateInfo extends EntryInfo { private String subjectDN; private Collection> subjectAN; private String issuer; private long startDate; private long expirationDate; private String algorithm; private int size; private String certificate; private EntryType type = EntryType.TRUSTED_CERTIFICATE; public CertificateInfo(String keystoreName, String alias) { super(keystoreName, alias); } public String getSubjectDN() { return this.subjectDN; } public void setSubjectDN(String subjectDN) { this.subjectDN = subjectDN; } public Collection> getSubjectAN() { return this.subjectAN; } public void setSubjectAN(Collection> subjectAN) { this.subjectAN = subjectAN; } public String getIssuer() { return this.issuer; } public void setIssuer(String issuer) { this.issuer = issuer; } public long getStartDate() { return this.startDate; } public void setStartDate(long startDate) { this.startDate = startDate; } public long getExpirationDate() { return this.expirationDate; } public void setExpirationDate(long expirationDate) { this.expirationDate = expirationDate; } public String getAlgorithm() { return this.algorithm; } public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public String getCertificate() { return this.certificate; } public void setCertificate(String certificate) { this.certificate = certificate; } public EntryType getType() { return this.type; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CertificateUtil.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.util; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Provider; import java.security.PublicKey; import java.security.Security; import java.security.cert.CertStore; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.bc.BcPEMDecryptorProvider; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.pkcs.PKCSException; import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.bouncycastle.util.Store; import org.bouncycastle.util.io.pem.PemObject; import org.bouncycastle.util.io.pem.PemReader; public class CertificateUtil { private CertificateUtil() { } public static java.security.cert.X509Certificate toJavaX509Certificate(Object o) throws Exception { CertificateFactory fac = CertificateFactory.getInstance("X509"); if (o instanceof X509CertificateHolder) { return (java.security.cert.X509Certificate) fac .generateCertificate(new ByteArrayInputStream(((X509CertificateHolder) o).getEncoded())); } else if (o instanceof X509Certificate) { return (java.security.cert.X509Certificate) fac .generateCertificate(new ByteArrayInputStream(((X509Certificate) o).getEncoded())); } else if (o instanceof java.security.cert.X509Certificate) { return (java.security.cert.X509Certificate) o; } else if (o instanceof PemObject) { return (java.security.cert.X509Certificate) fac .generateCertificate(new ByteArrayInputStream(((PemObject) o).getContent())); } throw new IllegalArgumentException("Object not one of X509CertificateHolder, X509Certificate or PemObject."); } public static Set toTrustAnchor(List certificates) throws Exception { Set out = new HashSet<>(); for (X509Certificate c : certificates) { out.add(new TrustAnchor(c, null)); } return out; } public static String x509CertificateToPem(final Certificate cert) throws IOException { final StringWriter writer = new StringWriter(); final JcaPEMWriter pemWriter = new JcaPEMWriter(writer); pemWriter.writeObject(cert); pemWriter.flush(); pemWriter.close(); return writer.toString(); } public static List readPemCertificates(String pemString) throws Exception { List certs = new ArrayList<>(); try (Reader r = new StringReader(pemString); PemReader reader = new PemReader(r);) { PemObject o; while ((o = reader.readPemObject()) != null) { certs.add(toJavaX509Certificate(o)); } } return certs; } /** * * @param pemString * String in PEM format with PKCS#8 syntax * @param password * @return * @throws IOException * @throws PKCSException */ public static PrivateKey readEncryptedPrivateKey(String pemString, String password) throws IOException, PKCSException { try (Reader r = new StringReader(pemString); PEMParser pemParser = new PEMParser(r);) { PrivateKeyInfo privateKeyInfo; JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); Object o = pemParser.readObject(); if (o instanceof PKCS8EncryptedPrivateKeyInfo) { PKCS8EncryptedPrivateKeyInfo epki = (PKCS8EncryptedPrivateKeyInfo) o; JcePKCSPBEInputDecryptorProviderBuilder builder = new JcePKCSPBEInputDecryptorProviderBuilder() .setProvider("BC"); InputDecryptorProvider idp = builder.build(password.toCharArray()); privateKeyInfo = epki.decryptPrivateKeyInfo(idp); } else if (o instanceof PEMEncryptedKeyPair) { PEMEncryptedKeyPair epki = (PEMEncryptedKeyPair) o; PEMKeyPair pkp = epki.decryptKeyPair(new BcPEMDecryptorProvider(password.toCharArray())); privateKeyInfo = pkp.getPrivateKeyInfo(); } else { throw new PKCSException("Invalid encrypted private key class: " + o.getClass().getName()); } return converter.getPrivateKey(privateKeyInfo); } } public static PublicKey readPublicKey(String pemString, String algorithm) throws Exception { KeyFactory factory = KeyFactory.getInstance(algorithm); try (Reader r = new StringReader(pemString); PemReader pemReader = new PemReader(r)) { PemObject pemObject = pemReader.readPemObject(); byte[] content = pemObject.getContent(); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content); return factory.generatePublic(pubKeySpec); } } public static X509Certificate[] generateCertificateChain(KeyPair keyPair, String signatureAlgorithm, String attributes, Date startDate, Date endDate) throws OperatorCreationException, CertificateException { Provider bcProvider = new BouncyCastleProvider(); Security.addProvider(bcProvider); X500Name dnName = new X500Name(attributes); // Use the timestamp as serial number BigInteger certSerialNumber = BigInteger.valueOf(System.currentTimeMillis()); SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded()); X509v3CertificateBuilder certificateBuilder = new X509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, subjectPublicKeyInfo); ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(bcProvider) .build(keyPair.getPrivate()); X509CertificateHolder certificateHolder = certificateBuilder.build(contentSigner); return new X509Certificate[] { new JcaX509CertificateConverter().getCertificate(certificateHolder) }; } @SuppressWarnings("unchecked") public static Store toX509CertificateHolderStore(String pemString) throws Exception { List certs = readPemCertificates(pemString); List x509CertificateHolderCerts = certs.stream().map(cert -> { try { return new X509CertificateHolder(cert.getEncoded()); } catch (CertificateEncodingException | IOException e) { throw new RuntimeException(e); } }).collect(Collectors.toList()); return new JcaCertStore(x509CertificateHolderCerts); } public static CertStore toCertStore(Store store) throws Exception { List certificatesX509 = store.getMatches(null).stream().map(t -> { try { return toJavaX509Certificate(t); } catch (Exception ignore) { } return null; }).collect(Collectors.toList()); try { return CertStore.getInstance("Collection", new CollectionCertStoreParameters(certificatesX509)); } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) { throw new Exception(e); } } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/CsrInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; public class CsrInfo extends EntryInfo { private String signatureAlgorithm; private String attributes; public CsrInfo(String keystoreServicePid, String alias) { super(keystoreServicePid, alias); } public String getSignatureAlgorithm() { return this.signatureAlgorithm; } public void setSignatureAlgorithm(String signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; } public String getAttributes() { return this.attributes; } public void setAttributes(String attributes) { this.attributes = attributes; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/EntryInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; public class EntryInfo { private final String keystoreServicePid; private final String alias; public EntryInfo(String keystoreServicePid, String alias) { this.keystoreServicePid = keystoreServicePid; this.alias = alias; } public String getKeystoreServicePid() { return this.keystoreServicePid; } public String getAlias() { return this.alias; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/EntryType.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.util; public enum EntryType { TRUSTED_CERTIFICATE, PRIVATE_KEY, KEY_PAIR, CSR; public static EntryType valueOfType(String type) { for (EntryType e : values()) { if (e.name().equals(type)) { return e; } } return null; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/KeyPairInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; public class KeyPairInfo extends EntryInfo { private String algorithm; private int size; private String signatureAlgorithm; private String attributes; public KeyPairInfo(String keystoreName, String alias) { super(keystoreName, alias); } public String getAlgorithm() { return this.algorithm; } public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public String getSignatureAlgorithm() { return this.signatureAlgorithm; } public void setSignatureAlgorithm(String signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; } public String getAttributes() { return this.attributes; } public void setAttributes(String attributes) { this.attributes = attributes; } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/KeystoreUtils.java ================================================ /******************************************************************************* * Copyright (c) 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStore.TrustedCertificateEntry; import java.security.PrivateKey; import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; public class KeystoreUtils { private KeystoreUtils() { // Empty constructor } public static PrivateKeyEntry createPrivateKey(String privateKey, String publicKey) throws IOException, GeneralSecurityException { // Works with RSA and DSA. EC is not supported since the certificate is encoded // with ECDSA while the corresponding private key with EC. // This cause an error when the PrivateKeyEntry is generated. Certificate[] certs = parsePublicCertificates(publicKey); Security.addProvider(new BouncyCastleProvider()); PEMParser pemParser = new PEMParser(new StringReader(privateKey)); Object object = pemParser.readObject(); pemParser.close(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); PrivateKey privkey = null; if (object instanceof org.bouncycastle.asn1.pkcs.PrivateKeyInfo) { privkey = converter.getPrivateKey((org.bouncycastle.asn1.pkcs.PrivateKeyInfo) object); } else if (object instanceof org.bouncycastle.openssl.PEMKeyPair) { privkey = converter.getKeyPair((org.bouncycastle.openssl.PEMKeyPair) object).getPrivate(); } else { throw new IOException("PrivateKey not recognized."); } return new PrivateKeyEntry(privkey, certs); } public static X509Certificate[] parsePublicCertificates(String certificates) throws CertificateException { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); ByteArrayInputStream is = new ByteArrayInputStream(certificates.getBytes(StandardCharsets.UTF_8)); final Collection decodedCertificates = certFactory.generateCertificates(is); final ArrayList result = new ArrayList<>(); for (final Certificate cert : decodedCertificates) { if (!(cert instanceof X509Certificate)) { throw new CertificateException("Provided certificate is not a X509Certificate"); } result.add((X509Certificate) cert); } return result.toArray(new X509Certificate[result.size()]); } public static TrustedCertificateEntry createCertificateEntry(String certificate) throws CertificateException { CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); ByteArrayInputStream is = new ByteArrayInputStream(certificate.getBytes(StandardCharsets.UTF_8)); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(is); return new TrustedCertificateEntry(cert); } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/MappingCollection.java ================================================ /******************************************************************************* * Copyright (c) 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.keystore.util; import java.util.Collection; import java.util.Iterator; import java.util.function.Function; import java.util.stream.Collectors; public class MappingCollection implements Collection { private final Collection source; private final Function func; public MappingCollection(final Collection source, final Function func) { this.source = source; this.func = func; } @Override public int size() { return source.size(); } @Override public boolean isEmpty() { return source.isEmpty(); } @Override public boolean contains(Object o) { return source.stream().map(func).collect(Collectors.toList()).contains(o); } @Override public Iterator iterator() { final Iterator iter = source.iterator(); return new Iterator() { @Override public boolean hasNext() { return iter.hasNext(); } @Override public U next() { return func.apply(iter.next()); } }; } @Override public Object[] toArray() { return source.stream().map(func).collect(Collectors.toList()).toArray(); } @Override public V[] toArray(V[] a) { return source.stream().map(func).collect(Collectors.toList()).toArray(a); } @Override public boolean add(U e) { throw new UnsupportedOperationException(); } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } } ================================================ FILE: kura/org.eclipse.kura.core.keystore/src/main/java/org/eclipse/kura/core/keystore/util/PrivateKeyInfo.java ================================================ /******************************************************************************* * Copyright (c) 2021, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * *******************************************************************************/ package org.eclipse.kura.core.keystore.util; public class PrivateKeyInfo extends EntryInfo { private String algorithm; private int size; private String privateKey; private String[] certificateChain; private EntryType type = EntryType.PRIVATE_KEY; public PrivateKeyInfo(String keystoreServicePid, String alias) { super(keystoreServicePid, alias); } public String getAlgorithm() { return this.algorithm; } public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } public int getSize() { return this.size; } public void setSize(int size) { this.size = size; } public String getPrivateKey() { return this.privateKey; } public void setPrivateKey(String privateKey) { this.privateKey = privateKey; } public String[] getCertificateChain() { return this.certificateChain; } public void setCertificateChain(String[] certificateChain) { this.certificateChain = certificateChain; } public EntryType getType() { return this.type; } } ================================================ FILE: kura/org.eclipse.kura.core.status/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.status Bundle-SymbolicName: org.eclipse.kura.core.status;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.3,2.0)", org.eclipse.kura.gpio;version="[1.0,2.0)", org.eclipse.kura.status;version="[1.0,1.1)", org.eclipse.kura.system;version="[1.0,2.0)", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.core.status/OSGI-INF/status.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.status/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.status/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.status/build.properties ================================================ # # Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # bin.includes = .,\ META-INF/,\ OSGI-INF/,\ about.html,\ about_files/ source.. = src/main/java/ additional.bundles = org.eclipse.kura.api,\ slf4j.api,\ org.eclipse.osgi,\ org.eclipse.kura.core src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.status/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.core.status 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.core.status.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/CloudConnectionStatusServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.status; import java.io.File; import java.util.HashSet; import java.util.Optional; import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.eclipse.kura.core.status.GpioLedManager.GpioIdentifier; import org.eclipse.kura.core.status.runnables.BlinkStatusRunnable; import org.eclipse.kura.core.status.runnables.HeartbeatStatusRunnable; import org.eclipse.kura.core.status.runnables.LogStatusRunnable; import org.eclipse.kura.core.status.runnables.OnOffStatusRunnable; import org.eclipse.kura.core.status.runnables.StatusRunnable; import org.eclipse.kura.gpio.GPIOService; import org.eclipse.kura.status.CloudConnectionStatusComponent; import org.eclipse.kura.status.CloudConnectionStatusEnum; import org.eclipse.kura.status.CloudConnectionStatusService; import org.eclipse.kura.system.SystemService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudConnectionStatusServiceImpl implements CloudConnectionStatusService { private static final String STATUS_NOTIFICATION_URL = "ccs.status.notification.url"; private static final Logger logger = LoggerFactory.getLogger(CloudConnectionStatusServiceImpl.class); private SystemService systemService; private Optional gpioService = Optional.empty(); private final ExecutorService notificationExecutor; private Future notificationWorker; private final IdleStatusComponent idleComponent; private CloudConnectionStatusEnum currentStatus = null; private final HashSet componentRegistry = new HashSet<>(); private Properties properties; private StatusRunnable statusRunnable; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public CloudConnectionStatusServiceImpl() { super(); this.notificationExecutor = Executors.newSingleThreadExecutor(); this.idleComponent = new IdleStatusComponent(); } public void setSystemService(SystemService systemService) { this.systemService = systemService; } public void unsetSystemService(SystemService systemService) { this.systemService = null; } public void setGPIOService(GPIOService gpioService) { this.gpioService = Optional.of(gpioService); } public void unsetGPIOService(GPIOService gpioService) { this.gpioService = Optional.empty(); } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { logger.info("Activating CloudConnectionStatus service..."); String urlFromConfig = this.systemService.getProperties().getProperty(STATUS_NOTIFICATION_URL, CloudConnectionStatusURL.CCS + CloudConnectionStatusURL.NONE); this.properties = CloudConnectionStatusURL.parseURL(urlFromConfig); register(this.idleComponent); } protected void deactivate(ComponentContext componentContext) { logger.info("Deactivating CloudConnectionStatus service..."); this.notificationExecutor.shutdownNow(); unregister(this.idleComponent); } // ---------------------------------------------------------------- // // Cloud Connection Status APIs // // ---------------------------------------------------------------- @Override public void register(CloudConnectionStatusComponent component) { this.componentRegistry.add(component); internalUpdateStatus(); } @Override public void unregister(CloudConnectionStatusComponent component) { this.componentRegistry.remove(component); internalUpdateStatus(); } @Override public boolean updateStatus(CloudConnectionStatusComponent component, CloudConnectionStatusEnum status) { try { component.setNotificationStatus(status); internalUpdateStatus(); } catch (Exception ex) { return false; } return true; } // ---------------------------------------------------------------- // // Private Methods // // ---------------------------------------------------------------- private void internalUpdateStatus() { CloudConnectionStatusComponent maxPriorityComponent = this.idleComponent; for (CloudConnectionStatusComponent c : this.componentRegistry) { if (c.getNotificationPriority() > maxPriorityComponent.getNotificationPriority()) { maxPriorityComponent = c; } } if (this.currentStatus == null || this.currentStatus != maxPriorityComponent.getNotificationStatus()) { this.currentStatus = maxPriorityComponent.getNotificationStatus(); if (this.statusRunnable != null) { this.statusRunnable.stopRunnable(); } if (this.notificationWorker != null) { this.notificationWorker.cancel(true); this.notificationWorker = null; } // Avoid NPE if CloudConnectionStatusComponent doesn't initialize its internal status. // Defaults to OFF this.currentStatus = this.currentStatus == null ? CloudConnectionStatusEnum.OFF : this.currentStatus; this.statusRunnable = getRunnable(this.currentStatus); this.notificationWorker = this.notificationExecutor.submit(this.statusRunnable); } } private StatusRunnable getRunnable(CloudConnectionStatusEnum status) { StatusRunnable runnable = null; StatusNotificationTypeEnum notificationType = Optional .ofNullable(this.properties.get(CloudConnectionStatusURL.NOTIFICATION_TYPE)) .filter(StatusNotificationTypeEnum.class::isInstance).map(StatusNotificationTypeEnum.class::cast) .orElseGet(() -> { logger.warn("Invalid {} property, disabiling cloud connection status notifications", STATUS_NOTIFICATION_URL); return StatusNotificationTypeEnum.NONE; }); switch (notificationType) { case LED: if (this.properties.get("linux_led") instanceof String) { runnable = getLinuxStatusWorker(status); } if (runnable == null && this.properties.get("led") instanceof GpioIdentifier) { runnable = getGpioStatusWorker(status); } if (runnable == null) { runnable = getLogStatusWorker(status); } break; case LOG: runnable = getLogStatusWorker(status); break; default: runnable = getNoneStatusWorker(); } return runnable; } private StatusRunnable getNoneStatusWorker() { return new StatusRunnable() { @Override public void run() { /* Empty runnable */ } @Override public void stopRunnable() { /* Empty runnable */ } }; } private StatusRunnable getLogStatusWorker(CloudConnectionStatusEnum status) { return new LogStatusRunnable(status); } private StatusRunnable getLinuxStatusWorker(CloudConnectionStatusEnum status) { StatusRunnable runnable = null; String ledPath = this.properties.getProperty("linux_led"); File f = new File(ledPath); if (f.exists() && f.isDirectory()) { LedManager linuxLedManager = new LinuxLedManager(ledPath); runnable = createLedRunnable(status, linuxLedManager); } return runnable; } private StatusRunnable getGpioStatusWorker(CloudConnectionStatusEnum status) { if (!this.gpioService.isPresent()) { return null; } final Object rawIdentifier = this.properties.get("led"); final GpioIdentifier identifier; if (rawIdentifier instanceof GpioIdentifier) { identifier = (GpioIdentifier) rawIdentifier; } else { throw new IllegalStateException("invaild gpio identifier: " + rawIdentifier); } final boolean inverted = Boolean.TRUE.equals(this.properties.get("inverted")); LedManager gpioLedManager = new GpioLedManager(this.gpioService.get(), identifier, inverted); return createLedRunnable(status, gpioLedManager); } private StatusRunnable createLedRunnable(CloudConnectionStatusEnum status, LedManager linuxLedManager) { StatusRunnable runnable; switch (status) { case ON: runnable = new OnOffStatusRunnable(linuxLedManager, true); break; case OFF: runnable = new OnOffStatusRunnable(linuxLedManager, false); break; case SLOW_BLINKING: runnable = new BlinkStatusRunnable(linuxLedManager); break; case FAST_BLINKING: runnable = new BlinkStatusRunnable(linuxLedManager); break; default: runnable = new HeartbeatStatusRunnable(linuxLedManager); } return runnable; } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/CloudConnectionStatusURL.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; import static java.util.Objects.requireNonNull; import java.util.Locale; import java.util.Properties; import org.eclipse.kura.core.status.GpioLedManager.GpioIdentifier; import org.eclipse.kura.core.status.GpioLedManager.GpioName; import org.eclipse.kura.core.status.GpioLedManager.GpioTerminal; public class CloudConnectionStatusURL { public static final String NOTIFICATION_TYPE = "notification_type"; public static final String CCS = "ccs:"; public static final String LED = "led:"; public static final String LED_NAME_PREFIX = "name:"; public static final String LED_TERMINAL_PREFIX = "terminal:"; public static final String LINUX_LED = "linux_led:"; public static final String LOG = "log"; public static final String NONE = "none"; public static final String INVERTED = ":inverted"; private static final String CASE_INSENSITIVE_PREFIX = "(?i)"; private static final String CCS_NOTIFICATION_URLS_SEPARATOR = ";"; private CloudConnectionStatusURL() { } public static Properties parseURL(String ccsUrl) { requireNonNull(ccsUrl); String urlImage = ccsUrl; Properties props = new Properties(); if (urlImage.toLowerCase(Locale.ENGLISH).startsWith(CCS)) { urlImage = urlImage.replaceAll(CASE_INSENSITIVE_PREFIX + CCS, ""); props.put("url", ccsUrl); String[] urls = urlImage.split(CCS_NOTIFICATION_URLS_SEPARATOR); for (String url : urls) { props.putAll(parseUrlType(url)); } } else { props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.NONE); } return props; } private static Properties parseUrlType(String urlImage) { Properties props = new Properties(); String urlLowerCase = urlImage.toLowerCase(Locale.ENGLISH); if (urlLowerCase.startsWith(LED)) { // Cloud Connection Status on LED String ledString = urlImage.substring(4); try { final boolean inverted = urlLowerCase.endsWith(INVERTED); if (inverted) { ledString = ledString.substring(0, ledString.length() - INVERTED.length()); } props.put("inverted", inverted); final GpioIdentifier identifier = parseLedIdentifier(ledString); props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LED); props.put("led", identifier); } catch (Exception ex) { // Do nothing } } else if (urlLowerCase.startsWith(LINUX_LED)) { String ledPath = urlImage.substring(LINUX_LED.length()); props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LED); props.put("linux_led", ledPath); } else if (urlLowerCase.startsWith(LOG)) { props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.LOG); } else if (urlLowerCase.startsWith(NONE)) { props.put(NOTIFICATION_TYPE, StatusNotificationTypeEnum.NONE); } return props; } private static GpioIdentifier parseLedIdentifier(final String identifier) { if (identifier.toLowerCase().startsWith(LED_NAME_PREFIX)) { final String name = identifier.substring(LED_NAME_PREFIX.length()); if (!name.isEmpty()) { return new GpioName(name); } } else { final String number; if (identifier.toLowerCase().startsWith(LED_TERMINAL_PREFIX)) { number = identifier.substring(LED_TERMINAL_PREFIX.length()); } else { number = identifier; } return new GpioTerminal(Integer.parseInt(number.trim())); } throw new IllegalArgumentException("invalid GPIO identifier " + identifier); } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/GpioLedManager.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; import java.io.IOException; import java.util.Objects; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.gpio.GPIOService; import org.eclipse.kura.gpio.KuraClosedDeviceException; import org.eclipse.kura.gpio.KuraGPIODeviceException; import org.eclipse.kura.gpio.KuraGPIODirection; import org.eclipse.kura.gpio.KuraGPIOMode; import org.eclipse.kura.gpio.KuraGPIOPin; import org.eclipse.kura.gpio.KuraGPIOTrigger; import org.eclipse.kura.gpio.KuraUnavailableDeviceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GpioLedManager implements LedManager { private static final Logger logger = LoggerFactory.getLogger(GpioLedManager.class); private final GpioIdentifier identifier; private final GPIOService gpioService; private final boolean inverted; public GpioLedManager(GPIOService gpioService, GpioIdentifier identifier) { this(gpioService, identifier, false); } public GpioLedManager(GPIOService gpioService, GpioIdentifier identifier, boolean inverted) { this.identifier = identifier; this.gpioService = gpioService; this.inverted = inverted; } public void writeLed(boolean enabled) throws KuraException { final KuraGPIOPin notificationLED; if (identifier instanceof GpioTerminal) { notificationLED = this.gpioService.getPinByTerminal(((GpioTerminal) identifier).getNumber(), KuraGPIODirection.OUTPUT, KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE); } else { notificationLED = this.gpioService.getPinByName(((GpioName) identifier).getName(), KuraGPIODirection.OUTPUT, KuraGPIOMode.OUTPUT_OPEN_DRAIN, KuraGPIOTrigger.NONE); } try { if (!notificationLED.isOpen()) { notificationLED.open(); logger.info("CloudConnectionStatus active on LED {}.", identifier); } notificationLED.setValue(enabled ^ inverted); } catch (KuraGPIODeviceException | KuraUnavailableDeviceException | IOException e) { logger.error("Error activating CloudConnectionStatus LED!"); throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE); } catch (KuraClosedDeviceException e) { logger.error("Error accessing to the specified LED!"); throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE); } } public interface GpioIdentifier { } public static class GpioTerminal implements GpioIdentifier { private final int number; public GpioTerminal(final int number) { this.number = number; } public int getNumber() { return number; } @Override public String toString() { return Integer.toString(number); } @Override public int hashCode() { return Objects.hash(number); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof GpioTerminal)) { return false; } GpioTerminal other = (GpioTerminal) obj; return number == other.number; } } public static class GpioName implements GpioIdentifier { private final String name; public GpioName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return name; } @Override public int hashCode() { return Objects.hash(name); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof GpioName)) { return false; } GpioName other = (GpioName) obj; return Objects.equals(name, other.name); } } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/IdleStatusComponent.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; import org.eclipse.kura.status.CloudConnectionStatusComponent; import org.eclipse.kura.status.CloudConnectionStatusEnum; import org.eclipse.kura.status.CloudConnectionStatusService; public class IdleStatusComponent implements CloudConnectionStatusComponent { @Override public int getNotificationPriority() { return CloudConnectionStatusService.PRIORITY_MIN; } @Override public CloudConnectionStatusEnum getNotificationStatus() { return CloudConnectionStatusEnum.OFF; } @Override public void setNotificationStatus(CloudConnectionStatusEnum status) { // We need a always present minimum priority status of OFF, se we don't want // the default notification status to be changed. // Do nothing } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/LedManager.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; import org.eclipse.kura.KuraException; public interface LedManager { public void writeLed(boolean enabled) throws KuraException; } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/LinuxLedManager.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LinuxLedManager implements LedManager { private static final Logger logger = LoggerFactory.getLogger(LinuxLedManager.class); private final String brightnessPath; public LinuxLedManager(String ledPath) { this.brightnessPath = ledPath + "/brightness"; } @Override public void writeLed(boolean enabled) throws KuraException { try (FileWriter ledFileWriter = new FileWriter(this.brightnessPath); BufferedWriter ledBufferedWriter = new BufferedWriter(ledFileWriter)) { if (enabled) { ledBufferedWriter.write("1"); } else { ledBufferedWriter.write("0"); } ledBufferedWriter.flush(); } catch (IOException e) { logger.error("Error accessing the specified LED!"); throw new KuraException(KuraErrorCode.UNAVAILABLE_DEVICE); } } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/StatusNotificationTypeEnum.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status; public enum StatusNotificationTypeEnum { LED, LOG, NONE; } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/BlinkStatusRunnable.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status.runnables; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.status.LedManager; import org.eclipse.kura.status.CloudConnectionStatusEnum; public class BlinkStatusRunnable implements StatusRunnable { private final LedManager ledManager; private boolean enabled; public BlinkStatusRunnable(LedManager ledManager) { this.ledManager = ledManager; this.enabled = true; } @Override public void run() { while (this.enabled) { try { this.ledManager.writeLed(true); Thread.sleep(CloudConnectionStatusEnum.SLOW_BLINKING_ON_TIME); this.ledManager.writeLed(false); Thread.sleep(CloudConnectionStatusEnum.SLOW_BLINKING_OFF_TIME); } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.enabled = false; } catch (KuraException e) { this.enabled = false; } } } @Override public void stopRunnable() { this.enabled = false; } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/HeartbeatStatusRunnable.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status.runnables; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.status.LedManager; import org.eclipse.kura.status.CloudConnectionStatusEnum; public class HeartbeatStatusRunnable implements StatusRunnable { private final LedManager ledManager; private boolean enabled; public HeartbeatStatusRunnable(LedManager ledManager) { this.ledManager = ledManager; this.enabled = true; } @Override public void run() { while (this.enabled) { try { this.ledManager.writeLed(true); Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_SYSTOLE_DURATION); this.ledManager.writeLed(false); Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_SYSTOLE_DURATION); this.ledManager.writeLed(true); Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_DIASTOLE_DURATION); this.ledManager.writeLed(false); Thread.sleep(CloudConnectionStatusEnum.HEARTBEAT_PAUSE_DURATION); } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.enabled = false; } catch (KuraException e) { this.enabled = false; } } } @Override public void stopRunnable() { this.enabled = false; } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/LogStatusRunnable.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status.runnables; import org.eclipse.kura.status.CloudConnectionStatusEnum; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogStatusRunnable implements StatusRunnable { private static final Logger logger = LoggerFactory.getLogger(LogStatusRunnable.class); private final CloudConnectionStatusEnum status; public LogStatusRunnable(CloudConnectionStatusEnum status) { this.status = status; } @Override public void run() { switch (this.status) { case ON: logger.info("Notification LED on"); break; case SLOW_BLINKING: logger.info("Notification LED slow blinking"); break; case FAST_BLINKING: logger.info("Notification LED fast blinking"); break; case HEARTBEAT: logger.info("Notification LED heartbeating"); break; default: logger.info("Notification LED off"); } } @Override public void stopRunnable() { return; } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/OnOffStatusRunnable.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status.runnables; import org.eclipse.kura.KuraException; import org.eclipse.kura.core.status.LedManager; import org.eclipse.kura.status.CloudConnectionStatusEnum; public class OnOffStatusRunnable implements StatusRunnable { private final LedManager ledManager; private boolean ledEnabled = false; private boolean enabled; public OnOffStatusRunnable(LedManager ledManager, boolean ledEnabled) { this.ledManager = ledManager; this.ledEnabled = ledEnabled; this.enabled = true; } @Override public void run() { while (this.enabled) { try { this.ledManager.writeLed(this.ledEnabled); Thread.sleep(CloudConnectionStatusEnum.PERIODIC_STATUS_CHECK_DELAY); } catch (InterruptedException e) { Thread.currentThread().interrupt(); this.enabled = false; } catch (KuraException e) { this.enabled = false; } } } @Override public void stopRunnable() { this.enabled = false; } } ================================================ FILE: kura/org.eclipse.kura.core.status/src/main/java/org/eclipse/kura/core/status/runnables/StatusRunnable.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.status.runnables; public interface StatusRunnable extends Runnable { public void stopRunnable(); } ================================================ FILE: kura/org.eclipse.kura.core.system/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.core.system Bundle-SymbolicName: org.eclipse.kura.core.system;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.apache.commons.io;version="[2.4,3.0)", org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.executor;version="[1.0,2.0)", org.eclipse.kura.net;version="[2.0,3.0)", org.eclipse.kura.system;version="[1.9,2.0)", org.osgi.framework;version="1.5.0", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" ================================================ FILE: kura/org.eclipse.kura.core.system/OSGI-INF/system.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.system/OSGI-INF/systemAdmin.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.core.system/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.core.system/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.core.system/build.properties ================================================ # # Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/,\ src/main/resources/ output.. = target/classes/ bin.includes = .,\ OSGI-INF/,\ META-INF/,\ about.html,\ about_files/ src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.core.system/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml org.eclipse.kura.core.system 2.0.0-SNAPSHOT eclipse-plugin ================================================ FILE: kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SuperSystemService.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.core.system; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandExecutorService; import org.eclipse.kura.executor.CommandStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Superclass of SystemService. */ @SuppressWarnings("checkstyle:hideUtilityClassConstructor") public class SuperSystemService { private static final Logger logger = LoggerFactory.getLogger(SuperSystemService.class); protected static String runSystemCommand(String[] commandLine, boolean runInShell, CommandExecutorService executorService, boolean allowFailure) { String response = ""; Command command = new Command(commandLine); command.setTimeout(60); command.setOutputStream(new ByteArrayOutputStream()); command.setExecuteInAShell(runInShell); CommandStatus status = executorService.execute(command); if (status.getExitStatus().isSuccessful() || allowFailure) { response = new String(((ByteArrayOutputStream) status.getOutputStream()).toByteArray(), StandardCharsets.UTF_8); } else { if (logger.isErrorEnabled()) { logger.error("failed to run commands {}", String.join(" ", commandLine)); } } return response; } protected static String runSystemCommand(String[] commandLine, boolean runInShell, CommandExecutorService executorService) { return runSystemCommand(commandLine, runInShell, executorService, false); } protected static String runSystemCommand(String commandLine, boolean runInShell, CommandExecutorService executorService, boolean allowFailure) { return runSystemCommand(commandLine.split("\\s+"), runInShell, executorService, allowFailure); } protected static String runSystemCommand(String commandLine, boolean runInShell, CommandExecutorService executorService) { return runSystemCommand(commandLine.split("\\s+"), runInShell, executorService); } } ================================================ FILE: kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SystemAdminServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2021 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.core.system; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandExecutorService; import org.eclipse.kura.executor.CommandStatus; import org.eclipse.kura.system.SystemAdminService; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SystemAdminServiceImpl extends SuperSystemService implements SystemAdminService { private static final Logger logger = LoggerFactory.getLogger(SystemAdminServiceImpl.class); private static final String OS_LINUX = "Linux"; private static final String OS_MAC_OSX = "Mac OS X"; private static final String OS_WINDOWS = "windows"; private static final String UNKNOWN = "UNKNOWN"; @SuppressWarnings("unused") private ComponentContext ctx; private CommandExecutorService executorService; // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setExecutorService(CommandExecutorService executorService) { this.executorService = executorService; } public void unsetExecutorService(CommandExecutorService executorService) { this.executorService = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- protected void activate(ComponentContext componentContext) { // // save the bundle context this.ctx = componentContext; } protected void deactivate(ComponentContext componentContext) { this.ctx = null; } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public String getUptime() { String uptimeStr = UNKNOWN; long uptime = 0; if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { try { String[] lastBootUpTime = runSystemCommand("wmic os get LastBootUpTime ", false, this.executorService) .split("\n"); if (lastBootUpTime[0].toLowerCase().startsWith("lastbootuptime")) { String lastBoot = lastBootUpTime[2]; DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); Date bootDate = df.parse(lastBoot); uptime = System.currentTimeMillis() - bootDate.getTime(); uptimeStr = Long.toString(uptime); } } catch (Exception e) { uptimeStr = "0"; logger.error("Could not read uptime", e); } } else if (OS_LINUX.equals(getOsName())) { File file; FileReader fr = null; BufferedReader br = null; try { file = new File("/proc/uptime"); fr = new FileReader(file); br = new BufferedReader(fr); String line = br.readLine(); if (line != null) { uptime = (long) (Double.parseDouble(line.substring(0, line.indexOf(" "))) * 1000); uptimeStr = Long.toString(uptime); } } catch (Exception e) { logger.error("Could not read uptime", e); } finally { if (br != null) { try { br.close(); } catch (IOException e) { } } if (fr != null) { try { fr.close(); } catch (IOException e) { } } } } else if (OS_MAC_OSX.equals(getOsName())) { try { String lastBootupSysCmd = runSystemCommand("sysctl -n kern.boottime", false, this.executorService); if (!lastBootupSysCmd.isEmpty()) { String[] uptimePairs = lastBootupSysCmd.substring(1, lastBootupSysCmd.indexOf("}")).replace(" ", "") .split(","); String[] uptimeSeconds = uptimePairs[0].split("="); uptime = System.currentTimeMillis() - (long) (Double.parseDouble(uptimeSeconds[1])); uptimeStr = Long.toString(uptime); } } catch (Exception e) { uptimeStr = "0"; logger.error("Could not read uptime", e); } } return uptimeStr; } @Override public void reboot() { if (OS_LINUX.equals(getOsName()) || OS_MAC_OSX.equals(getOsName())) { executeCommand(new String[] { "reboot" }); } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { executeCommand(new String[] { "shutdown", "-r" }); } else { logger.error("Unsupported OS for reboot()"); } } @Override public void sync() { if (OS_LINUX.equals(getOsName()) || OS_MAC_OSX.equals(getOsName())) { executeCommand(new String[] { "sync" }); } else { logger.error("Unsupported OS for sync()"); } } private void executeCommand(String[] cmd) { Command command = new Command(cmd); command.setTimeout(60); CommandStatus status = this.executorService.execute(command); if (status.getExitStatus().isSuccessful()) { logger.error("failed to issue {} command", cmd[0]); } } private String getOsName() { return System.getProperty("os.name"); } } ================================================ FILE: kura/org.eclipse.kura.core.system/src/main/java/org/eclipse/kura/core/system/SystemServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2011, 2026 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.core.system; import static java.lang.Thread.currentThread; import static java.util.Objects.isNull; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.StandardProtocolFamily; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Properties; import java.util.StringJoiner; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.eclipse.kura.KuraProcessExecutionErrorException; import org.eclipse.kura.executor.Command; import org.eclipse.kura.executor.CommandExecutorService; import org.eclipse.kura.executor.CommandStatus; import org.eclipse.kura.net.NetInterfaceStatus; import org.eclipse.kura.system.ExtendedProperties; import org.eclipse.kura.system.InternetConnectionStatus; import org.eclipse.kura.system.SystemResourceInfo; import org.eclipse.kura.system.SystemResourceType; import org.eclipse.kura.system.SystemService; import org.osgi.framework.Bundle; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.ComponentException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SystemServiceImpl extends SuperSystemService implements SystemService { private ScheduledExecutorService internetCheckerExecutor; private static final String DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_IP = "198.41.30.198"; private static final String DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_HOST = "eclipse.org"; private static final String SYS_CLASS_NET = "/sys/class/net/"; private static final Logger logger = LoggerFactory.getLogger(SystemServiceImpl.class); private static final String PROPERTY_PROVIDER_SUFFIX = ".provider"; private static final String DMIDECODE_COMMAND = "dmidecode -t system"; private static final String SPACES_REGEX = ":\\s+"; private static final String BIN_SH = "/bin/sh"; private static final String LINUX_2_6_34_12_WR4_3_0_0_STANDARD = "2.6.34.12-WR4.3.0.0_standard"; private static final String LINUX_2_6_34_9_WR4_2_0_0_STANDARD = "2.6.34.9-WR4.2.0.0_standard"; private static final String CLOUDBEES_SECURITY_SETTINGS_PATH = "/private/eurotech/settings-security.xml"; private static final String LOG4J_CONFIGURATION = "log4j.configuration"; private static final String DPA_CONFIGURATION = "dpa.configuration"; private static final String KURA_PATH = "/opt/eclipse/kura"; private static final String OS_WINDOWS = "windows"; private static final int INTERNET_CHECK_TIME_INTERVAL = 30000; private static boolean onCloudbees = false; private Properties kuraProperties; private ComponentContext componentContext; private CommandExecutorService executorService; private String primaryInterfaceMacAddress; private final AtomicReference currentInternetStatus = new AtomicReference<>( InternetConnectionStatus.UNAVAILABLE); private ScheduledFuture currentTask; public void setExecutorService(CommandExecutorService executorService) { this.executorService = executorService; } public void unsetExecutorService(CommandExecutorService executorService) { this.executorService = null; } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- @SuppressWarnings({ "rawtypes", "unchecked", "checkstyle:methodLength" }) protected void activate(ComponentContext componentContext) { this.componentContext = componentContext; AccessController.doPrivileged((PrivilegedAction) () -> { try { // privileged code goes here, for example: onCloudbees = new File(CLOUDBEES_SECURITY_SETTINGS_PATH).exists(); return null; // nothing to return } catch (Exception e) { logger.warn("Unable to execute privileged in SystemService"); return null; } }); // load the defaults from the kura.properties files Properties kuraDefaults = new Properties(); boolean updateTriggered = false; try { // special cases for older versions to fix relative path bug in v2.0.4 and earlier if (System.getProperty(KURA_CONFIG) != null && System.getProperty(KURA_CONFIG).trim().equals("file:kura/kura.properties")) { System.setProperty(KURA_CONFIG, "file:/opt/eclipse/kura/framework/kura.properties"); updateTriggered = true; logger.warn("Overridding invalid kura.properties location"); } if (System.getProperty(DPA_CONFIGURATION) != null && System.getProperty(DPA_CONFIGURATION).trim().equals("kura/dpa.properties")) { System.setProperty(DPA_CONFIGURATION, "/opt/eclipse/kura/packages/dpa.properties"); updateTriggered = true; logger.warn("Overridding invalid dpa.properties location"); } if (System.getProperty(LOG4J_CONFIGURATION) != null && System.getProperty(LOG4J_CONFIGURATION).trim().equals("file:kura/log4j.properties")) { System.setProperty(LOG4J_CONFIGURATION, "file:/opt/eclipse/kura/user/log4j.properties"); updateTriggered = true; logger.warn("Overridding invalid log4j.properties location"); } // load the default kura.properties // look for kura.properties as resource in the classpath // if not found, look for such file in the kura.home directory String kuraHome = System.getProperty(KEY_KURA_HOME_DIR); String kuraFrameworkConfig = System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR); String kuraUserConfig = System.getProperty(KEY_KURA_USER_CONFIG_DIR); String kuraConfig = System.getProperty(KURA_CONFIG); String kuraProps = readResource(KURA_PROPS_FILE); if (kuraProps != null) { kuraDefaults.load(new StringReader(kuraProps)); logger.info("Loaded Jar Resource kura.properties."); } else if (kuraConfig != null) { loadKuraDefaults(kuraDefaults, kuraConfig); } else if (kuraFrameworkConfig != null) { File kuraPropsFile = new File(kuraFrameworkConfig + File.separator + KURA_PROPS_FILE); if (kuraPropsFile.exists()) { try (final FileReader fr = new FileReader(kuraPropsFile)) { kuraDefaults.load(fr); } logger.info("Loaded File kura.properties: {}", kuraPropsFile); } else { logger.warn("File does not exist: {}", kuraPropsFile); } } else { logger.error("Could not locate kura.properties file"); } // Try to reload kuraHome with the value set in kura.properties file. if (kuraHome == null) { kuraHome = kuraDefaults.getProperty(KEY_KURA_HOME_DIR); } // Try to reload kuraFrameworkConfig with the value set in kura.properties file. if (kuraFrameworkConfig == null) { kuraFrameworkConfig = kuraDefaults.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR); } // Try to reload kurauserConfig with the value set in kura.properties file. if (kuraUserConfig == null) { kuraUserConfig = kuraDefaults.getProperty(KEY_KURA_USER_CONFIG_DIR); } // load custom kura properties // look for kura_custom.properties as resource in the classpath // if not found, look for such file in the kura.user.config directory Properties kuraCustomProps = new Properties(); String kuraCustomConfig = System.getProperty(KURA_CUSTOM_CONFIG); String kuraCustomProperties = readResource(KURA_CUSTOM_PROPS_FILE); if (kuraCustomProperties != null) { kuraCustomProps.load(new StringReader(kuraCustomProperties)); logger.info("Loaded Jar Resource: {}", KURA_CUSTOM_PROPS_FILE); } else if (kuraCustomConfig != null) { loadKuraCustom(kuraCustomProps, kuraCustomConfig); } else if (kuraUserConfig != null) { File kuraCustomPropsFile = new File(kuraUserConfig + File.separator + KURA_CUSTOM_PROPS_FILE); if (kuraCustomPropsFile.exists()) { Reader reader = new FileReader(kuraCustomPropsFile); try { kuraCustomProps.load(reader); } finally { reader.close(); } logger.info("Loaded File {}: {}", KURA_CUSTOM_PROPS_FILE, kuraCustomPropsFile); } else { logger.warn("File does not exist: {}", kuraCustomPropsFile); } } else { logger.info("Did not locate a kura_custom.properties file in {}", kuraUserConfig); } // Override defaults with values from kura_custom.properties kuraDefaults.putAll(kuraCustomProps); // more path overrides based on earlier Kura problem with relative paths if (kuraDefaults.getProperty(KEY_KURA_HOME_DIR) != null && kuraDefaults.getProperty(KEY_KURA_HOME_DIR).trim().equals("kura")) { kuraDefaults.setProperty(KEY_KURA_HOME_DIR, KURA_PATH); updateTriggered = true; logger.warn("Overridding invalid kura.home location"); } if (kuraDefaults.getProperty(KEY_KURA_PLUGINS_DIR) != null && kuraDefaults.getProperty(KEY_KURA_PLUGINS_DIR).trim().equals("kura/plugins")) { kuraDefaults.setProperty(KEY_KURA_PLUGINS_DIR, "/opt/eclipse/kura/plugins"); updateTriggered = true; logger.warn("Overridding invalid kura.plugins location"); } if (kuraDefaults.getProperty(KEY_KURA_PACKAGES_DIR) != null && kuraDefaults.getProperty(KEY_KURA_PACKAGES_DIR).trim().equals("kura/packages")) { kuraDefaults.setProperty(KEY_KURA_PACKAGES_DIR, "/opt/eclipse/kura/data/packages"); updateTriggered = true; logger.warn("Overridding invalid kura.packages location"); } if (updateTriggered) { File directory; // Desired current working directory directory = new File(KURA_PATH).getAbsoluteFile(); if (directory.exists() || directory.mkdirs()) { String oldDir = System.getProperty("user.dir"); if (System.setProperty("user.dir", directory.getAbsolutePath()) != null) { logger.warn("Changed working directory to /opt/eclipse/kura from {}", oldDir); } } } // build the m_kuraProperties instance with the defaults this.kuraProperties = new Properties(kuraDefaults); // take care of the CloudBees environment // that is run in the continuous integration. if (onCloudbees) { this.kuraProperties.put(KEY_OS_NAME, OS_CLOUDBEES); } // Put the Net Admin and Web interface availability property so that is available through a get. Boolean hasNetAdmin = Boolean.valueOf(this.kuraProperties.getProperty(KEY_KURA_HAVE_NET_ADMIN, "true")); this.kuraProperties.put(KEY_KURA_HAVE_NET_ADMIN, hasNetAdmin); logger.info("Kura has net admin? {}", hasNetAdmin); String webInterfaceEnabled = this.kuraProperties.getProperty(KEY_KURA_HAVE_WEB_INTER, "true"); this.kuraProperties.put(KEY_KURA_HAVE_WEB_INTER, webInterfaceEnabled); logger.info("Is Kura web interface enabled? {}", webInterfaceEnabled); String kuraVersion = this.kuraProperties.getProperty(KEY_KURA_VERSION, "version-unknown"); this.kuraProperties.put(KEY_KURA_VERSION, kuraVersion); logger.info("Kura version? {}", kuraVersion); if (System.getProperty(KEY_KURA_NAME) != null) { this.kuraProperties.put(KEY_KURA_NAME, System.getProperty(KEY_KURA_NAME)); } if (System.getProperty(KEY_KURA_VERSION) != null) { this.kuraProperties.put(KEY_KURA_VERSION, System.getProperty(KEY_KURA_VERSION)); } if (System.getProperty(KEY_DEVICE_NAME) != null) { this.kuraProperties.put(KEY_DEVICE_NAME, System.getProperty(KEY_DEVICE_NAME)); } if (System.getProperty(KEY_PLATFORM) != null) { this.kuraProperties.put(KEY_PLATFORM, System.getProperty(KEY_PLATFORM)); } if (System.getProperty(KEY_MODEL_ID) != null) { this.kuraProperties.put(KEY_MODEL_ID, System.getProperty(KEY_MODEL_ID)); } if (System.getProperty(KEY_MODEL_NAME) != null) { this.kuraProperties.put(KEY_MODEL_NAME, System.getProperty(KEY_MODEL_NAME)); } if (System.getProperty(KEY_PART_NUMBER) != null) { this.kuraProperties.put(KEY_PART_NUMBER, System.getProperty(KEY_PART_NUMBER)); } if (System.getProperty(KEY_SERIAL_NUM) != null) { this.kuraProperties.put(KEY_SERIAL_NUM, System.getProperty(KEY_SERIAL_NUM)); } if (System.getProperty(KEY_BIOS_VERSION) != null) { this.kuraProperties.put(KEY_BIOS_VERSION, System.getProperty(KEY_BIOS_VERSION)); } if (System.getProperty(KEY_FIRMWARE_VERSION) != null) { this.kuraProperties.put(KEY_FIRMWARE_VERSION, System.getProperty(KEY_FIRMWARE_VERSION)); } if (System.getProperty(KEY_PRIMARY_NET_IFACE) != null) { this.kuraProperties.put(KEY_PRIMARY_NET_IFACE, System.getProperty(KEY_PRIMARY_NET_IFACE)); } if (System.getProperty(KEY_KURA_HOME_DIR) != null) { this.kuraProperties.put(KEY_KURA_HOME_DIR, System.getProperty(KEY_KURA_HOME_DIR)); } if (System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR) != null) { this.kuraProperties.put(KEY_KURA_FRAMEWORK_CONFIG_DIR, System.getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR)); } if (System.getProperty(KEY_KURA_USER_CONFIG_DIR) != null) { this.kuraProperties.put(KEY_KURA_USER_CONFIG_DIR, System.getProperty(KEY_KURA_USER_CONFIG_DIR)); } if (System.getProperty(KEY_KURA_PLUGINS_DIR) != null) { this.kuraProperties.put(KEY_KURA_PLUGINS_DIR, System.getProperty(KEY_KURA_PLUGINS_DIR)); } if (System.getProperty(KEY_KURA_PACKAGES_DIR) != null) { this.kuraProperties.put(KEY_KURA_PACKAGES_DIR, System.getProperty(KEY_KURA_PACKAGES_DIR)); } if (System.getProperty(KEY_KURA_DATA_DIR) != null) { this.kuraProperties.put(KEY_KURA_DATA_DIR, System.getProperty(KEY_KURA_DATA_DIR)); } if (System.getProperty(KEY_KURA_TMP_DIR) != null) { this.kuraProperties.put(KEY_KURA_TMP_DIR, System.getProperty(KEY_KURA_TMP_DIR)); } if (System.getProperty(KEY_KURA_SNAPSHOTS_DIR) != null) { this.kuraProperties.put(KEY_KURA_SNAPSHOTS_DIR, System.getProperty(KEY_KURA_SNAPSHOTS_DIR)); } if (System.getProperty(KEY_KURA_SNAPSHOTS_COUNT) != null) { this.kuraProperties.put(KEY_KURA_SNAPSHOTS_COUNT, System.getProperty(KEY_KURA_SNAPSHOTS_COUNT)); } if (System.getProperty(KEY_KURA_HAVE_NET_ADMIN) != null) { this.kuraProperties.put(KEY_KURA_HAVE_NET_ADMIN, System.getProperty(KEY_KURA_HAVE_NET_ADMIN)); } if (System.getProperty(KEY_KURA_HAVE_WEB_INTER) != null) { this.kuraProperties.put(KEY_KURA_HAVE_WEB_INTER, System.getProperty(KEY_KURA_HAVE_WEB_INTER)); } if (System.getProperty(KEY_KURA_STYLE_DIR) != null) { this.kuraProperties.put(KEY_KURA_STYLE_DIR, System.getProperty(KEY_KURA_STYLE_DIR)); } if (System.getProperty(KEY_KURA_WIFI_TOP_CHANNEL) != null) { this.kuraProperties.put(KEY_KURA_WIFI_TOP_CHANNEL, System.getProperty(KEY_KURA_WIFI_TOP_CHANNEL)); } if (System.getProperty(KEY_KURA_KEY_STORE_PWD) != null) { this.kuraProperties.put(KEY_KURA_KEY_STORE_PWD, System.getProperty(KEY_KURA_KEY_STORE_PWD)); } if (System.getProperty(KEY_KURA_TRUST_STORE_PWD) != null) { this.kuraProperties.put(KEY_KURA_TRUST_STORE_PWD, System.getProperty(KEY_KURA_TRUST_STORE_PWD)); } if (System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_SIZE) != null) { this.kuraProperties.put(KEY_FILE_COMMAND_ZIP_MAX_SIZE, System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_SIZE)); } if (System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_NUMBER) != null) { this.kuraProperties.put(KEY_FILE_COMMAND_ZIP_MAX_NUMBER, System.getProperty(KEY_FILE_COMMAND_ZIP_MAX_NUMBER)); } if (System.getProperty(KEY_OS_ARCH) != null) { this.kuraProperties.put(KEY_OS_ARCH, System.getProperty(KEY_OS_ARCH)); } if (System.getProperty(KEY_OS_NAME) != null) { this.kuraProperties.put(KEY_OS_NAME, System.getProperty(KEY_OS_NAME)); } if (System.getProperty(KEY_OS_VER) != null) { this.kuraProperties.put(KEY_OS_VER, getOsVersion()); // System.getProperty(KEY_OS_VER) } if (System.getProperty(KEY_OS_DISTRO) != null) { this.kuraProperties.put(KEY_OS_DISTRO, System.getProperty(KEY_OS_DISTRO)); } if (System.getProperty(KEY_OS_DISTRO_VER) != null) { this.kuraProperties.put(KEY_OS_DISTRO_VER, System.getProperty(KEY_OS_DISTRO_VER)); } if (System.getProperty(KEY_JAVA_VERSION) != null) { this.kuraProperties.put(KEY_JAVA_VERSION, System.getProperty(KEY_JAVA_VERSION)); } if (System.getProperty(KEY_JAVA_VENDOR) != null) { this.kuraProperties.put(KEY_JAVA_VENDOR, System.getProperty(KEY_JAVA_VENDOR)); } if (System.getProperty(KEY_JAVA_VM_NAME) != null) { this.kuraProperties.put(KEY_JAVA_VM_NAME, System.getProperty(KEY_JAVA_VM_NAME)); } if (System.getProperty(KEY_JAVA_VM_VERSION) != null) { this.kuraProperties.put(KEY_JAVA_VM_VERSION, System.getProperty(KEY_JAVA_VM_VERSION)); } if (System.getProperty(KEY_JAVA_VM_INFO) != null) { this.kuraProperties.put(KEY_JAVA_VM_INFO, System.getProperty(KEY_JAVA_VM_INFO)); } if (System.getProperty(KEY_JAVA_VM_VENDOR) != null) { this.kuraProperties.put(KEY_JAVA_VM_VENDOR, System.getProperty(KEY_JAVA_VM_VENDOR)); } if (System.getProperty(KEY_JDK_VENDOR_VERSION) != null) { this.kuraProperties.put(KEY_JDK_VENDOR_VERSION, System.getProperty(KEY_JDK_VENDOR_VERSION)); } if (System.getProperty(KEY_OSGI_FW_NAME) != null) { this.kuraProperties.put(KEY_OSGI_FW_NAME, System.getProperty(KEY_OSGI_FW_NAME)); } if (System.getProperty(KEY_OSGI_FW_VERSION) != null) { this.kuraProperties.put(KEY_OSGI_FW_VERSION, System.getProperty(KEY_OSGI_FW_VERSION)); } if (System.getProperty(KEY_JAVA_HOME) != null) { this.kuraProperties.put(KEY_JAVA_HOME, System.getProperty(KEY_JAVA_HOME)); } if (System.getProperty(KEY_FILE_SEP) != null) { this.kuraProperties.put(KEY_FILE_SEP, System.getProperty(KEY_FILE_SEP)); } if (System.getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE) != null) { this.kuraProperties.put(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE, System.getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE)); } if (System.getProperty(DB_URL_PROPNAME) != null) { this.kuraProperties.put(DB_URL_PROPNAME, System.getProperty(DB_URL_PROPNAME)); } if (System.getProperty(DB_CACHE_ROWS_PROPNAME) != null) { this.kuraProperties.put(DB_CACHE_ROWS_PROPNAME, System.getProperty(DB_CACHE_ROWS_PROPNAME)); } if (System.getProperty(DB_LOB_FILE_PROPNAME) != null) { this.kuraProperties.put(DB_LOB_FILE_PROPNAME, System.getProperty(DB_LOB_FILE_PROPNAME)); } if (System.getProperty(DB_DEFRAG_LIMIT_PROPNAME) != null) { this.kuraProperties.put(DB_DEFRAG_LIMIT_PROPNAME, System.getProperty(DB_DEFRAG_LIMIT_PROPNAME)); } if (System.getProperty(DB_LOG_DATA_PROPNAME) != null) { this.kuraProperties.put(DB_LOG_DATA_PROPNAME, System.getProperty(DB_LOG_DATA_PROPNAME)); } if (System.getProperty(DB_LOG_SIZE_PROPNAME) != null) { this.kuraProperties.put(DB_LOG_SIZE_PROPNAME, System.getProperty(DB_LOG_SIZE_PROPNAME)); } if (System.getProperty(DB_NIO_PROPNAME) != null) { this.kuraProperties.put(DB_NIO_PROPNAME, System.getProperty(DB_NIO_PROPNAME)); } if (System.getProperty(DB_WRITE_DELAY_MILLIES_PROPNAME) != null) { this.kuraProperties.put(DB_WRITE_DELAY_MILLIES_PROPNAME, System.getProperty(DB_WRITE_DELAY_MILLIES_PROPNAME)); } if (System.getProperty(KEY_CPU_VERSION) != null) { this.kuraProperties.put(KEY_CPU_VERSION, System.getProperty(KEY_CPU_VERSION)); } if (System.getProperty(KEY_COMMAND_USER) != null) { this.kuraProperties.put(KEY_COMMAND_USER, System.getProperty(KEY_COMMAND_USER)); } if (System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST) != null) { this.kuraProperties.put(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST, System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST)); } if (System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP) != null) { this.kuraProperties.put(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP, System.getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP)); } if (getKuraHome() == null) { logger.error("Did not initialize kura.home"); } else { logger.info("Kura home directory is {}", getKuraHome()); createDirIfNotExists(getKuraHome()); } if (getKuraFrameworkConfigDirectory() == null) { logger.error("Did not initialize kura.framework.config"); } else { logger.info("Kura framework configuration directory is {}", getKuraFrameworkConfigDirectory()); createDirIfNotExists(getKuraFrameworkConfigDirectory()); } if (getKuraUserConfigDirectory() == null) { logger.error("Did not initialize kura.user.config"); } else { logger.info("Kura user configuration directory is {}", getKuraUserConfigDirectory()); createDirIfNotExists(getKuraUserConfigDirectory()); } if (getKuraSnapshotsDirectory() == null) { logger.error("Did not initialize kura.snapshots"); } else { logger.info("Kura snapshots directory is {}", getKuraSnapshotsDirectory()); createDirIfNotExists(getKuraSnapshotsDirectory()); } if (getKuraTemporaryConfigDirectory() == null) { logger.error("Did not initialize kura.tmp"); } else { logger.info("Kura tmp directory is {}", getKuraTemporaryConfigDirectory()); createDirIfNotExists(getKuraTemporaryConfigDirectory()); } logger.info("Kura version {} is starting", getKuraVersion()); } catch (IOException e) { throw new ComponentException("Error loading default properties", e); } this.internetCheckerExecutor = Executors.newSingleThreadScheduledExecutor(r -> { final Thread result = Executors.defaultThreadFactory().newThread(r); result.setName("internet-status-checker"); return result; }); this.currentTask = this.internetCheckerExecutor.scheduleAtFixedRate(this::checkInternetTask, 5000, INTERNET_CHECK_TIME_INTERVAL, TimeUnit.MILLISECONDS); } private void loadKuraCustom(Properties kuraCustomProps, String kuraCustomConfig) { try { final URL kuraConfigUrl = new URL(kuraCustomConfig); try (InputStream in = kuraConfigUrl.openStream()) { kuraCustomProps.load(in); } logger.info("Loaded URL kura_custom.properties: {}", kuraCustomConfig); } catch (Exception e) { logger.warn("Could not open kuraCustomConfig URL: ", e); } } private void loadKuraDefaults(Properties kuraDefaults, String kuraConfig) { try { final URL kuraConfigUrl = new URL(kuraConfig); try (InputStream in = kuraConfigUrl.openStream()) { kuraDefaults.load(in); } logger.info("Loaded URL kura.properties: {}", kuraConfig); } catch (Exception e) { logger.warn("Could not open kuraConfig URL", e); } } protected String readResource(String resource) throws IOException { if (resource == null) { return null; } final URL resourceUrl = currentThread().getContextClassLoader().getResource(resource); if (resourceUrl == null) { return null; } return IOUtils.toString(resourceUrl); } protected void deactivate(ComponentContext componentContext) { this.componentContext = null; this.kuraProperties = null; if (this.currentTask != null) { this.currentTask.cancel(true); } if (this.internetCheckerExecutor != null) { this.internetCheckerExecutor.shutdown(); try { this.internetCheckerExecutor.awaitTermination(5000, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { currentThread().interrupt(); this.internetCheckerExecutor.shutdownNow(); } } } public void updated(Map properties) { // nothing to do // all properties of the System service are read-only } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- /** * Returns all KuraProperties for this system. The returned instances is * initialized by loading the kura.properties file. Properties defined at * the System level - for example using the java -D command line flag - * are used to overwrite the values loaded from the kura.properties file * in a hierarchical configuration fashion. */ @Override public Properties getProperties() { return this.kuraProperties; } @Override public String getPrimaryMacAddress() { String primaryNetworkInterfaceName = getPrimaryNetworkInterfaceName(); if (OS_MAC_OSX.equals(getOsName())) { return getPrimaryMacAddressOSX(primaryNetworkInterfaceName); } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { return getPrimaryMacAddressWindows(primaryNetworkInterfaceName); } else { return getPrimaryMacAddressLinux(primaryNetworkInterfaceName); } } private String getPrimaryMacAddressOSX(String primaryNetworkInterfaceName) { String macAddress = null; try { logger.info("executing: ifconfig and looking for {}", primaryNetworkInterfaceName); List out = Arrays .asList(runSystemCommand("ifconfig", false, this.executorService).split("\\r?\\n")); ListIterator iterator = out.listIterator(); String line; while (iterator.hasNext()) { line = iterator.next(); if (line.startsWith(primaryNetworkInterfaceName)) { // get the next line and save the MAC line = iterator.next(); if (line == null) { throw new IOException("Null input!"); } if (!line.trim().startsWith("ether")) { line = iterator.next(); } String[] splitLine = line.split(" "); if (splitLine.length > 0) { macAddress = splitLine[1].toUpperCase(); } } } } catch (IOException e) { logger.error("Failed to get network interfaces", e); } return macAddress; } private String getPrimaryMacAddressWindows(String primaryNetworkInterfaceName) { if (!isNull(this.primaryInterfaceMacAddress)) { return this.primaryInterfaceMacAddress; } try { logger.info("executing: InetAddress.getLocalHost {}", primaryNetworkInterfaceName); InetAddress ip = InetAddress.getLocalHost(); // Windows options are either ethX or wlanX, and eth0 may really not be the correct one InetAddress ip2 = getPrimaryIPWindows("eth"); if (ip2 == null) { ip2 = getPrimaryIPWindows("wlan"); } if (ip2 != null) { ip = ip2; } NetworkInterface network = NetworkInterface.getByInetAddress(ip); byte[] mac = network.getHardwareAddress(); this.primaryInterfaceMacAddress = hardwareAddressToString(mac); logger.info("macAddress {}", this.primaryInterfaceMacAddress); } catch (UnknownHostException | SocketException e) { logger.error(e.getLocalizedMessage()); } return this.primaryInterfaceMacAddress; } private String getPrimaryMacAddressLinux(String primaryNetworkInterfaceName) { if (!isNull(this.primaryInterfaceMacAddress)) { return this.primaryInterfaceMacAddress; } try { Optional interfaceSysfsDir = Optional.empty(); try (final DirectoryStream s = Files.newDirectoryStream(new File(SYS_CLASS_NET).toPath())) { for (final Path p : s) { final File file = p.toFile(); if (Objects.equals(primaryNetworkInterfaceName, file.getName().split("@")[0])) { interfaceSysfsDir = Optional.of(file); break; } } } if (!interfaceSysfsDir.isPresent()) { logger.error("Failed to find primary network interface"); return null; } try (final FileInputStream in = new FileInputStream(new File(interfaceSysfsDir.get(), "address")); final BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) { this.primaryInterfaceMacAddress = r.readLine().trim().toUpperCase(); } } catch (final Exception e) { logger.error("Failed to get network interface address", e); return null; } return this.primaryInterfaceMacAddress; } /** * Returns ip of the first interface name of which begins with prefix. * * @param prefix * network interface name prefix e.g. eth, wlan * @return ip of the first interface name of which begins with prefix; null if none found with ip * @throws SocketException */ private InetAddress getPrimaryIPWindows(String prefix) throws SocketException { InetAddress ip = null; Enumeration networks = NetworkInterface.getNetworkInterfaces(); while (networks.hasMoreElements()) { NetworkInterface network = networks.nextElement(); if (network.getName().startsWith(prefix)) { Enumeration ips = network.getInetAddresses(); if (ips.hasMoreElements()) { ip = ips.nextElement(); break; } } } return ip; } @Override public String getPrimaryNetworkInterfaceName() { final Optional propertyValue = getProperty(KEY_PRIMARY_NET_IFACE); if (propertyValue.isPresent()) { return propertyValue.get(); } else { if (OS_MAC_OSX.equals(getOsName())) { return "en0"; } else if (OS_LINUX.equals(getOsName())) { return "eth0"; } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { return OS_WINDOWS; } else { logger.error("Unsupported platform"); return null; } } } @Override public String getPlatform() { return getProperty(KEY_PLATFORM).orElse(null); } @Override public String getOsArch() { final Optional override = getProperty(KEY_OS_ARCH); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_OS_ARCH); } @Override public String getOsName() { final Optional override = getProperty(KEY_OS_NAME); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_OS_NAME); } @Override public String getOsVersion() { final Optional override = getProperty(KEY_OS_VER); if (override.isPresent()) { return override.get(); } StringBuilder sbOsVersion = new StringBuilder(); sbOsVersion.append(System.getProperty(KEY_OS_VER)); if (OS_LINUX.equals(getOsName())) { File linuxKernelVersion = null; linuxKernelVersion = new File("/proc/sys/kernel/version"); if (linuxKernelVersion.exists()) { StringBuilder kernelVersionData = new StringBuilder(); try (FileReader fr = new FileReader(linuxKernelVersion); BufferedReader in = new BufferedReader(fr)) { String tempLine = null; while ((tempLine = in.readLine()) != null) { kernelVersionData.append(" "); kernelVersionData.append(tempLine); } sbOsVersion.append(kernelVersionData.toString()); } catch (IOException e) { logger.error("Failed to get OS version", e); } } } return sbOsVersion.toString(); } @Override public String getOsDistro() { return getProperty(KEY_OS_DISTRO).orElse(null); } @Override public String getOsDistroVersion() { return getProperty(KEY_OS_DISTRO_VER).orElse(null); } @Override public String getJavaVendor() { final Optional override = getProperty(KEY_JAVA_VENDOR); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VENDOR); } @Override public String getJavaVersion() { final Optional override = getProperty(KEY_JAVA_VERSION); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VERSION); } @Override public String getJavaVmName() { final Optional override = getProperty(KEY_JAVA_VM_NAME); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VM_NAME); } @Override public String getJavaVmVersion() { final Optional override = getProperty(KEY_JAVA_VM_VERSION); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VM_VERSION); } @Override public String getJavaVmInfo() { final Optional override = getProperty(KEY_JAVA_VM_INFO); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VM_INFO); } @Override public String getOsgiFwName() { final Optional override = getProperty(KEY_OSGI_FW_NAME); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_OSGI_FW_NAME); } @Override public String getOsgiFwVersion() { final Optional override = getProperty(KEY_OSGI_FW_VERSION); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_OSGI_FW_VERSION); } @Override public int getNumberOfProcessors() { try { return Runtime.getRuntime().availableProcessors(); } catch (Throwable t) { // NoSuchMethodError on pre-1.4 runtimes } return -1; } @Override public long getTotalMemory() { return Runtime.getRuntime().totalMemory() / 1024; } @Override public long getFreeMemory() { return Runtime.getRuntime().freeMemory() / 1024; } @Override public String getFileSeparator() { final Optional override = getProperty(KEY_FILE_SEP); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_FILE_SEP); } @Override public String getJavaHome() { final Optional override = getProperty(KEY_JAVA_HOME); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_HOME); } public String getKuraName() { return getProperty(KEY_KURA_NAME).orElse(null); } @Override public String getKuraVersion() { return getProperty(KEY_KURA_VERSION).orElse(null); } @Override public String getKuraMarketplaceCompatibilityVersion() { final Optional override = getProperty(KEY_KURA_MARKETPLACE_COMPATIBILITY_VERSION); final String marketplaceCompatibilityVersion; if (override.isPresent()) { marketplaceCompatibilityVersion = override.get(); } else { marketplaceCompatibilityVersion = getKuraVersion(); } return marketplaceCompatibilityVersion.replaceAll("KURA[-_ ]", "").replaceAll("[-_]", "."); } @Override public String getKuraFrameworkConfigDirectory() { return getProperty(KEY_KURA_FRAMEWORK_CONFIG_DIR).orElse(null); } @Override public String getKuraUserConfigDirectory() { return getProperty(KEY_KURA_USER_CONFIG_DIR).orElse(null); } @Override public String getKuraHome() { return getProperty(KEY_KURA_HOME_DIR).orElse(null); } public String getKuraPluginsDirectory() { return getProperty(KEY_KURA_PLUGINS_DIR).orElse(null); } @Override public String getKuraDataDirectory() { return getProperty(KEY_KURA_DATA_DIR).orElse(null); } @Override public String getKuraTemporaryConfigDirectory() { return getProperty(KEY_KURA_TMP_DIR).orElse(null); } @Override public String getKuraSnapshotsDirectory() { return getProperty(KEY_KURA_SNAPSHOTS_DIR).orElse(null); } @Override public int getKuraSnapshotsCount() { return getIntegerPropertyValue(KEY_KURA_SNAPSHOTS_COUNT, 10); } @Override public int getKuraWifiTopChannel() { return getIntegerPropertyValue(KEY_KURA_WIFI_TOP_CHANNEL, Integer.MAX_VALUE); } @Override public String getKuraStyleDirectory() { return getProperty(KEY_KURA_STYLE_DIR).orElse(null); } @Override public String getKuraWebEnabled() { return getProperty(KEY_KURA_HAVE_WEB_INTER).orElse(null); } @Override public int getFileCommandZipMaxUploadSize() { return getIntegerPropertyValue(KEY_FILE_COMMAND_ZIP_MAX_SIZE, 100); } @Override public int getFileCommandZipMaxUploadNumber() { return getIntegerPropertyValue(KEY_FILE_COMMAND_ZIP_MAX_NUMBER, 1024); } @Override public String getBiosVersion() { final Optional override = getProperty(KEY_BIOS_VERSION); if (override.isPresent()) { return override.get(); } String biosVersion = UNSUPPORTED; if (OS_LINUX.equals(getOsName())) { if (LINUX_2_6_34_9_WR4_2_0_0_STANDARD.equals(getOsVersion()) || LINUX_2_6_34_12_WR4_3_0_0_STANDARD.equals(getOsVersion())) { biosVersion = runSystemCommand("eth_vers_bios", false, this.executorService); } else { String biosTmp = runSystemCommand("dmidecode -s bios-version", false, this.executorService); if (biosTmp.length() > 0 && !biosTmp.contains("Permission denied")) { biosVersion = biosTmp; } } } else if (OS_MAC_OSX.equals(getOsName())) { String[] cmds = { BIN_SH, "-c", "system_profiler SPHardwareDataType | grep 'Boot ROM'" }; String biosTmp = runSystemCommand(cmds, true, this.executorService); if (biosTmp.contains(": ")) { biosVersion = biosTmp.split(SPACES_REGEX)[1]; } } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { String[] cmds = { "wmic", "bios", "get", "smbiosbiosversion" }; String biosTmp = runSystemCommand(cmds, false, this.executorService); if (biosTmp.contains("SMBIOSBIOSVersion")) { biosVersion = biosTmp.split("SMBIOSBIOSVersion\\s+")[1]; biosVersion = biosVersion.trim(); } } return biosVersion; } @Override public String getDeviceName() { final Optional override = getProperty(KEY_DEVICE_NAME); if (override.isPresent()) { return override.get(); } String deviceName = UNKNOWN; if (OS_MAC_OSX.equals(getOsName())) { String displayTmp = runSystemCommand("scutil --get ComputerName", false, this.executorService); if (displayTmp.length() > 0) { deviceName = displayTmp; } } else if (OS_LINUX.equals(getOsName()) || OS_CLOUDBEES.equals(getOsName()) || getOsName().toLowerCase().startsWith(OS_WINDOWS)) { String displayTmp = runSystemCommand("hostname", false, this.executorService); if (displayTmp.length() > 0) { deviceName = displayTmp; } } return deviceName; } @Override public String getFirmwareVersion() { final Optional override = getProperty(KEY_FIRMWARE_VERSION); if (override.isPresent()) { return override.get(); } String fwVersion = UNSUPPORTED; if (OS_LINUX.equals(getOsName()) && getOsVersion() != null) { if (getOsVersion().startsWith(LINUX_2_6_34_9_WR4_2_0_0_STANDARD) || getOsVersion().startsWith(LINUX_2_6_34_12_WR4_3_0_0_STANDARD)) { fwVersion = runSystemCommand("eth_vers_cpld", false, this.executorService) + " " + runSystemCommand("eth_vers_uctl", false, this.executorService); } else if (getOsVersion().startsWith("3.0.35-12.09.01+yocto")) { fwVersion = runSystemCommand("eth_vers_avr", false, this.executorService); } } return fwVersion; } @Override public String getModelId() { final Optional override = getProperty(KEY_MODEL_ID); if (override.isPresent()) { return override.get(); } String modelId = UNKNOWN; if (OS_MAC_OSX.equals(getOsName())) { String modelTmp = runSystemCommand("sysctl -b hw.model", false, this.executorService); if (modelTmp.length() > 0) { modelId = modelTmp; } } else if (OS_LINUX.equals(getOsName())) { String modelTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService); if (modelTmp.contains("Version: ")) { modelId = modelTmp.split("Version:\\s+")[1].split("\n")[0]; } } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { String[] cmds = { "wmic", "baseboard", "get", "Version" }; String biosTmp = runSystemCommand(cmds, false, this.executorService); if (biosTmp.contains("Version")) { modelId = biosTmp.split("Version\\s+")[1]; modelId = modelId.trim(); } } return modelId; } @Override public String getModelName() { final Optional override = getProperty(KEY_MODEL_NAME); if (override.isPresent()) { return override.get(); } String modelName = UNKNOWN; if (OS_MAC_OSX.equals(getOsName())) { String[] cmds = { BIN_SH, "-c", "system_profiler SPHardwareDataType | grep 'Model Name'" }; String modelTmp = runSystemCommand(cmds, true, this.executorService); if (modelTmp.contains(": ")) { modelName = modelTmp.split(SPACES_REGEX)[1]; } } else if (OS_LINUX.equals(getOsName())) { String modelTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService); if (modelTmp.contains("Product Name: ")) { modelName = modelTmp.split("Product Name:\\s+")[1].split("\n")[0]; } } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { String[] cmds = { "wmic", "baseboard", "get", "Product" }; String biosTmp = runSystemCommand(cmds, false, this.executorService); if (biosTmp.contains("Product")) { modelName = biosTmp.split("Product\\s+")[1]; modelName = modelName.trim(); } } return modelName; } @Override public String getPartNumber() { final Optional override = getProperty(KEY_PART_NUMBER); if (override.isPresent()) { return override.get(); } String partNumber = UNSUPPORTED; if (OS_LINUX.equals(getOsName()) && (LINUX_2_6_34_9_WR4_2_0_0_STANDARD.equals(getOsVersion()) || LINUX_2_6_34_12_WR4_3_0_0_STANDARD.equals(getOsVersion()))) { partNumber = runSystemCommand("eth_partno_bsp", false, this.executorService) + " " + runSystemCommand("eth_partno_epr", false, this.executorService); } return partNumber; } @Override public String getSerialNumber() { final Optional override = getProperty(KEY_SERIAL_NUM); if (override.isPresent()) { return override.get(); } String serialNum = UNKNOWN; if (OS_MAC_OSX.equals(getOsName())) { String[] cmds = { BIN_SH, "-c", "system_profiler SPHardwareDataType | grep 'Serial Number'" }; String serialTmp = runSystemCommand(cmds, true, this.executorService); if (serialTmp.contains(": ")) { serialNum = serialTmp.split(SPACES_REGEX)[1]; } } else if (OS_LINUX.equals(getOsName())) { String serialTmp = runSystemCommand(DMIDECODE_COMMAND, false, this.executorService); if (serialTmp.contains("Serial Number: ")) { serialNum = serialTmp.split("Serial Number:\\s+")[1].split("\n")[0]; } } else if (getOsName().toLowerCase().startsWith(OS_WINDOWS)) { String[] cmds = { "wmic", "bios", "get", "SerialNumber" }; String biosTmp = runSystemCommand(cmds, false, this.executorService); if (biosTmp.contains("SerialNumber")) { serialNum = biosTmp.split("SerialNumber\\s+")[1]; serialNum = serialNum.trim(); } } return serialNum; } @Override public char[] getJavaKeyStorePassword() { final Optional keyStorePwd = getProperty(KEY_KURA_KEY_STORE_PWD); if (keyStorePwd.isPresent()) { return keyStorePwd.get().toCharArray(); } return new char[0]; } @Override public char[] getJavaTrustStorePassword() { final Optional trustStorePwd = getProperty(KEY_KURA_TRUST_STORE_PWD); if (trustStorePwd.isPresent()) { return trustStorePwd.get().toCharArray(); } return new char[0]; } @Override public Bundle[] getBundles() { if (this.componentContext == null) { return null; } return this.componentContext.getBundleContext().getBundles(); } @Override public List getSystemPackages() throws KuraProcessExecutionErrorException { List packagesInfo = new ArrayList<>(); CommandStatus debStatus = execute(new String[] { "dpkg-query", "-W" }); if (debStatus.getExitStatus().isSuccessful() && ((ByteArrayOutputStream) debStatus.getOutputStream()).size() > 0) { parseSystemPackages(packagesInfo, debStatus, SystemResourceType.DEB); } CommandStatus rpmStatus = execute( new String[] { "rpm", "-qa", "--queryformat", "'%{NAME} %{VERSION}-%{RELEASE}\n'" }); if (rpmStatus.getExitStatus().isSuccessful() && ((ByteArrayOutputStream) rpmStatus.getOutputStream()).size() > 0) { parseSystemPackages(packagesInfo, rpmStatus, SystemResourceType.RPM); } CommandStatus apkStatus = execute(new String[] { "apk", "list", "-I", "|", "awk", "'{ print $1 }'" }); if (apkStatus.getExitStatus().isSuccessful() && ((ByteArrayOutputStream) apkStatus.getOutputStream()).size() > 0) { parseSystemPackages(packagesInfo, apkStatus, SystemResourceType.APK); } if (!debStatus.getExitStatus().isSuccessful() && !rpmStatus.getExitStatus().isSuccessful() && !apkStatus.getExitStatus().isSuccessful()) { throw new KuraProcessExecutionErrorException("Failed to retrieve system packages."); } return packagesInfo; } private void parseSystemPackages(List packagesInfo, CommandStatus status, SystemResourceType type) { String[] packages = new String(((ByteArrayOutputStream) status.getOutputStream()).toByteArray(), StandardCharsets.UTF_8).split("\n"); Arrays.asList(packages).stream().forEach(p -> { String[] fields = p.split("\\s+"); // this works for dpkg and rpm where separator for version and name is a // sequence of spaces if (fields.length >= 2) { packagesInfo.add(new SystemResourceInfo(fields[0], fields[1], type)); } else { // apk case: need more complex parsing String[] nameAndVersion = getApkNameAndVersion(fields[0]); packagesInfo.add(new SystemResourceInfo(nameAndVersion[0], nameAndVersion[1], type)); } }); } /** * An APK package name consists of the name and the version separated by "-". * The name and the version itself can contain "-". * Assumptions are that the fullName starts with the package name and ends with the version. * * @param fullName * of the APK software package, e.g. "busybox-extras-1.31.1-r10" * @return String array with name in position 0 and version in position 1 */ private String[] getApkNameAndVersion(String fullName) { String[] split = fullName.split("-"); StringBuilder name = new StringBuilder(); StringBuilder version = new StringBuilder(); int matchIndex = 1000; Pattern pattern = Pattern.compile("^([0-9]+.?)"); for (int i = 0; i < split.length; i++) { String s = split[i]; // version is never at the beginning if (i > 0 && i < matchIndex) { if (pattern.matcher(s).lookingAt()) { version.append(s); matchIndex = i; } else { name.append("-"); name.append(s); } } // everything else after match is version if (i > matchIndex) { version.append("-"); version.append(s); } } return new String[] { split[0] + name.toString(), version.toString() }; } private CommandStatus execute(String[] commandLine) { Command command = new Command(commandLine); command.setExecuteInAShell(true); ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream err = new ByteArrayOutputStream(); command.setErrorStream(err); command.setOutputStream(out); CommandStatus status = this.executorService.execute(command); if (logger.isDebugEnabled()) { logger.debug("execute command {} :: exited with code - {}", command, status.getExitStatus().getExitCode()); logger.debug("execute stderr {}", new String(err.toByteArray(), StandardCharsets.UTF_8)); logger.debug("execute stdout {}", new String(out.toByteArray(), StandardCharsets.UTF_8)); } return status; } @Override public List getDeviceManagementServiceIgnore() { final Optional servicesToIgnore = getProperty(CONFIG_CONSOLE_DEVICE_MANAGE_SERVICE_IGNORE); List services = new ArrayList<>(); if (servicesToIgnore.isPresent() && !servicesToIgnore.get().trim().isEmpty()) { String[] servicesArray = servicesToIgnore.get().split(","); if (servicesArray != null && servicesArray.length > 0) { services = Arrays.asList(servicesArray); } } return services; } // ---------------------------------------------------------------- // // Private Methods // // ---------------------------------------------------------------- private static void createDirIfNotExists(String fileName) { // Make sure the configuration directory exists - create it if not File file = new File(fileName); if (!file.exists() && !file.mkdirs()) { logger.error("Failed to create the temporary configuration directory: {}", fileName); if (Boolean.getBoolean("org.eclipse.kura.core.dontExitOnFailure")) { throw new RuntimeException( String.format("Failed to create the temporary configuration directory: %s", fileName)); } System.exit(-1); } } @Override public String getHostname() { String hostname = UNKNOWN; if (OS_MAC_OSX.equals(getOsName())) { hostname = runSystemCommand("scutil --get ComputerName", false, this.executorService); } else if (OS_LINUX.equals(getOsName()) || OS_CLOUDBEES.equals(getOsName()) || getOsName().toLowerCase().startsWith(OS_WINDOWS)) { hostname = runSystemCommand("hostname", false, this.executorService); } return hostname; } @Override public String getNetVirtualDevicesConfig() { String status = NetInterfaceStatus.netIPv4StatusDisabled.name(); String virtualDefaultConfig = this.kuraProperties.getProperty(KEY_KURA_NET_VIRTUAL_DEVICES_CONFIG); if (virtualDefaultConfig != null && virtualDefaultConfig.equalsIgnoreCase("unmanaged")) { status = NetInterfaceStatus.netIPv4StatusUnmanaged.name(); } return status; } private static String hardwareAddressToString(byte[] macAddress) { if (macAddress == null) { return "N/A"; } if (macAddress.length != 6) { throw new IllegalArgumentException("macAddress is invalid"); } StringJoiner sj = new StringJoiner(":"); for (byte item : macAddress) { sj.add(String.format("%02X", item)); } return sj.toString(); } @Override public String getCpuVersion() { final Optional override = getProperty(KEY_CPU_VERSION); if (override.isPresent()) { return override.get(); } if (OS_LINUX.equals(getOsName())) { try { return probeCpuVersionLinux(); } catch (final Exception e) { // do nothing } } return "unknown"; } private static String probeCpuVersionLinux() throws IOException { try (final BufferedReader reader = new BufferedReader(new FileReader("/proc/cpuinfo"))) { String line; while ((line = reader.readLine()) != null) { final int separatorIndex = line.indexOf(':'); if (separatorIndex == -1) { continue; } final String key = line.substring(0, separatorIndex).trim(); if (key.equals("model name")) { return line.substring(separatorIndex + 1).trim(); } } } throw new IOException("Could not retrieve cpu version"); } protected Optional getProperty(final String key) { final String prop = this.kuraProperties.getProperty(key); if (prop != null) { return Optional.of(prop); } final String externalProvider = this.kuraProperties.getProperty(key + PROPERTY_PROVIDER_SUFFIX); if (externalProvider != null) { final String result = processCommandOutput(runSystemCommand(externalProvider, true, this.executorService)); if (result != null && !result.isEmpty()) { return Optional.of(result); } } return Optional.empty(); } private String processCommandOutput(final String result) { if (result == null) { return null; } final String trimmed = result.trim(); if (trimmed.isEmpty()) { return trimmed; } int i; for (i = trimmed.length() - 1; i > 0; i--) { if (trimmed.charAt(i) != '\n') { break; } } return trimmed.substring(0, i + 1); } @Override public Optional getExtendedProperties() { return Optional.empty(); } @Override public String getCommandUser() { final Optional override = getProperty(KEY_COMMAND_USER); if (override.isPresent()) { return override.get(); } return "unknown"; } @Override public boolean isLegacyBluetoothBeaconScan() { final Optional override = getProperty(KEY_LEGACY_BT_BEACON_SCAN); if (override.isPresent()) { return Boolean.parseBoolean(override.get()); } return false; } @Override public boolean isLegacyPPPLoggingEnabled() { final Optional override = getProperty(KEY_LEGACY_PPP_LOGGING); if (override.isPresent()) { return Boolean.parseBoolean(override.get()); } return false; } @Override public String getJavaVmVendor() { final Optional override = getProperty(KEY_JAVA_VM_VENDOR); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JAVA_VM_VENDOR); } @Override public String getJdkVendorVersion() { final Optional override = getProperty(KEY_JDK_VENDOR_VERSION); if (override.isPresent()) { return override.get(); } return System.getProperty(KEY_JDK_VENDOR_VERSION); } @Override public Optional getDefaultLogManager() { return getProperty(KEY_DEFAULT_LOG_MANAGER); } @Override public boolean isWPA3WifiSecurityEnabled() { final Optional isWPA3enabled = getProperty(KEY_WPA3_WIFI_SECURITY_ENABLE); if (isWPA3enabled.isPresent()) { return Boolean.parseBoolean(isWPA3enabled.get()); } return false; } @Override public int getNetworkConfigurationTimeout() { return getIntegerPropertyValue(KEY_NETWORK_CONFIGURATION_TIMEOUT, 30); } @Override public String getInternetConnectionStatusCheckHost() { return getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_HOST) .orElse(DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_HOST); } @Override public String getInternetConnectionStatusCheckIp() { return getProperty(KEY_INTERNET_CONNECTION_STATUS_CHECK_IP).orElse(DEFAULT_INTERNET_CONNECTION_STATUS_CHECK_IP); } private int getIntegerPropertyValue(String propertyName, int defaultValue) { final Optional propertyValue = getProperty(propertyName); if (propertyValue.isPresent() && !propertyValue.get().trim().isEmpty()) { try { return Integer.parseInt(propertyValue.get()); } catch (NumberFormatException e) { logger.error("Cannot parse integer value for property {}: {}. Set it to default {}.", propertyName, propertyValue.get(), defaultValue, e); } } return defaultValue; } @Override public InternetConnectionStatus getInternetConnectionStatus() { return this.currentInternetStatus.get(); } private void checkInternetTask() { if (this.executorService == null) { return; } InternetConnectionStatus oldStatus = this.currentInternetStatus.get(); try { if (isPingable(StandardProtocolFamily.INET, getInternetConnectionStatusCheckHost()) || isPingable(StandardProtocolFamily.INET6, getInternetConnectionStatusCheckHost())) { updateStatus(oldStatus, InternetConnectionStatus.FULL); return; } if (isPingable(StandardProtocolFamily.INET, getInternetConnectionStatusCheckIp()) || isPingable(StandardProtocolFamily.INET6, getInternetConnectionStatusCheckIp())) { updateStatus(oldStatus, InternetConnectionStatus.IP_ONLY); return; } updateStatus(oldStatus, InternetConnectionStatus.UNAVAILABLE); } catch (Exception e) { logger.error("Error while checking internet connection status", e); } } private void updateStatus(InternetConnectionStatus oldStatus, InternetConnectionStatus newStatus) { this.currentInternetStatus.set(newStatus); if (newStatus != oldStatus) { logger.debug("Internet connection status changed to {}", newStatus); } } private boolean isPingable(StandardProtocolFamily protocol, String address) { String version; switch (protocol) { case INET: version = "-4"; break; case INET6: version = "-6"; break; default: throw new IllegalArgumentException("Unexpected protocol: " + protocol); } try { // -c 5: send 5 ping requests, // -W 5: wait for 1 seconds max for each reply CommandStatus status = this.executorService .execute(new Command(new String[] { "ping", version, address, "-c", "5", "-W", "1" })); return status.getExitStatus().isSuccessful(); } catch (Exception e) { logger.trace("Error while executing ping command", e); return false; } } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/.gitignore ================================================ lib/ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.db.h2db.provider Bundle-SymbolicName: org.eclipse.kura.db.h2db.provider;singleton:=true Bundle-Version: 1.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.7,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.connection.listener;version="1.0.0", org.eclipse.kura.crypto;version="1.3.0", org.eclipse.kura.data;version="[1.1,2.0)", org.eclipse.kura.db;version="[2.0,2.1)", org.eclipse.kura.message.store;version="[1.0,2.0)", org.eclipse.kura.message.store.provider;version="[1.0,1.1)", org.eclipse.kura.type;version="[1.1,2.0)", org.eclipse.kura.util.configuration;version="[1.0,1.1)", org.eclipse.kura.util.jdbc;version="[1.0,2.0)", org.eclipse.kura.util.message.store;version="[1.0,2.0)", org.eclipse.kura.util.store.listener;version="[1.0,2.0)", org.eclipse.kura.util.wire.store;version="[1.0,1.1)", org.eclipse.kura.wire;version="[2.0,3.0)", org.eclipse.kura.wire.store.provider;version="[1.0,1.1)", org.h2;version="2.4.240", org.h2.api;version="2.4.240", org.h2.jdbcx;version="2.4.240", org.h2.tools;version="2.4.240", org.osgi.framework;version="1.10.0", org.osgi.service.component;version="1.4.0", org.slf4j;version="1.7.32" ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/h2db.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/h2dbserver.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/metatype/org.eclipse.kura.core.db.H2DbServer.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/OSGI-INF/metatype/org.eclipse.kura.core.db.H2DbService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/build.properties ================================================ # # Copyright (c) 2024 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about_files/,\ about.html src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.db.h2db.provider 1.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbMessageStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.io.ByteArrayInputStream; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.sql.Types; import java.util.Date; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.message.store.StoredMessage; import org.eclipse.kura.message.store.StoredMessage.Builder; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.jdbc.JdbcUtil; import org.eclipse.kura.util.message.store.AbstractJdbcMessageStoreImpl; import org.eclipse.kura.util.message.store.JdbcMessageStoreQueries; import org.h2.api.ErrorCode; @SuppressWarnings("restriction") public class H2DbMessageStoreImpl extends AbstractJdbcMessageStoreImpl { private static final String CREATE_INDEX_IF_NOT_EXISTS = "CREATE INDEX IF NOT EXISTS "; private static final String UPDATE = "UPDATE "; private static final String DELETE_FROM = "DELETE FROM "; private static final String SELECT_MESSAGE_METADATA_FROM = "SELECT id, topic, qos, retain, createdOn, publishedOn, " + "publishedMessageId, confirmedOn, priority, sessionId, droppedOn FROM "; private static final String ALTER_TABLE = "ALTER TABLE "; private static final int PAYLOAD_BYTE_SIZE_THRESHOLD = 200; /** * The error with code 22003 is thrown when a value is out of range when * converting to another data type. */ private static final int NUMERIC_VALUE_OUT_OF_RANGE_1 = 22003; /** * The error with code 22004 is thrown when a value is out of range when * converting to another column's data type. */ private static final int NUMERIC_VALUE_OUT_OF_RANGE_2 = 22004; private String sqlSetNextId; private String sqlGetFreeId; public H2DbMessageStoreImpl(final ConnectionProvider provider, final String table) throws KuraStoreException { super(provider, table); initDb(); } private void initDb() throws KuraStoreException { this.sqlSetNextId = ALTER_TABLE + super.escapedTableName + " ALTER COLUMN id RESTART WITH ?;"; this.sqlGetFreeId = "SELECT A.X FROM SYSTEM_RANGE(1, 2147483647) AS A LEFT OUTER JOIN " + this.escapedTableName + " AS B ON A.X = B.ID WHERE B.ID IS NULL LIMIT 1"; super.createTable(); super.createIndexes(); } @Override protected JdbcMessageStoreQueries buildSqlMessageStoreQueries() { return JdbcMessageStoreQueries.builder().withSqlCreateTable("CREATE TABLE IF NOT EXISTS " + super.escapedTableName + " (id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, topic VARCHAR(32767 CHARACTERS), qos INTEGER, retain BOOLEAN, " + "createdOn TIMESTAMP, publishedOn TIMESTAMP, publishedMessageId INTEGER, confirmedOn TIMESTAMP, " + "smallPayload VARBINARY, largePayload BLOB(16777216), priority INTEGER," + " sessionId VARCHAR(32767 CHARACTERS), droppedOn TIMESTAMP);") .withSqlMessageCount("SELECT COUNT(*) FROM " + super.escapedTableName + ";") .withSqlStore("INSERT INTO " + super.escapedTableName + " (topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, smallPayload, largePayload, priority, " + "sessionId, droppedOn) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);") .withSqlGetMessage( "SELECT id, topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, " + "smallPayload, largePayload, priority, sessionId, droppedOn FROM " + this.escapedTableName + " WHERE id = ?") .withSqlGetNextMessage("SELECT a.id, a.topic, a.qos, a.retain, a.createdOn, a.publishedOn, " + "a.publishedMessageId, a.confirmedOn, a.smallPayload, a.largePayload, a.priority, a.sessionId, a.droppedOn FROM " + this.escapedTableName + " AS a JOIN (SELECT id, publishedOn FROM " + super.escapedTableName + " ORDER BY publishedOn ASC NULLS FIRST, priority ASC, createdOn ASC LIMIT 1) AS b " + "WHERE a.id = b.id AND b.publishedOn IS NULL;") .withSqlSetPublishedQoS1(UPDATE + super.escapedTableName + " SET publishedOn = ?, publishedMessageId = ?, sessionId = ? WHERE id = ?;") .withSqlSetPublishedQoS0(UPDATE + super.escapedTableName + " SET publishedOn = ? WHERE id = ?;") .withSqlSetConfirmed(UPDATE + this.escapedTableName + " SET confirmedOn = ? WHERE id = ?;") .withSqlAllUnpublishedMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE publishedOn IS NULL ORDER BY priority ASC, createdOn ASC;") .withSqlAllInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL AND droppedOn IS NULL " + "ORDER BY priority ASC, createdOn ASC") .withSqlAllDroppedInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE droppedOn IS NOT NULL ORDER BY priority ASC, createdOn ASC;") .withSqlUnpublishAllInFlightMessages(UPDATE + super.escapedTableName + " SET publishedOn = NULL WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;") .withSqlDropAllInFlightMessages(UPDATE + super.escapedTableName + " SET droppedOn = ? WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;") .withSqlDeleteDroppedMessages(DELETE_FROM + super.escapedTableName + " WHERE droppedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND droppedOn IS NOT NULL;") .withSqlDeleteConfirmedMessages(DELETE_FROM + super.escapedTableName + " WHERE confirmedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND confirmedOn IS NOT NULL;") .withSqlDeletePublishedMessages(DELETE_FROM + super.escapedTableName + " WHERE qos = 0 AND publishedOn <= DATEADD('MILLISECOND', ?, TIMESTAMP '1970-01-01 00:00:00') AND publishedOn IS NOT NULL;") .withSqlCreateNextMessageIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_nextMsg") + " ON " + super.escapedTableName + " (publishedOn ASC, priority ASC, createdOn ASC, qos);") .withSqlCreatePublishedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_PUBLISHEDON") + " ON " + this.escapedTableName + " (publishedOn DESC);") .withSqlCreateConfirmedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_CONFIRMEDON") + " ON " + this.escapedTableName + " (confirmedOn DESC);") .withSqlCreateDroppedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_DROPPEDON") + " ON " + this.escapedTableName + " (droppedOn DESC);") .build(); } @Override public synchronized int store(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException { validate(topic); try { return (int) storeInternal(topic, payload, qos, retain, priority); } catch (KuraStoreException e) { handleKuraStoreException(e); return (int) storeInternal(topic, payload, qos, retain, priority); } } private void handleKuraStoreException(final KuraStoreException e) throws KuraStoreException { final Throwable cause = e.getCause(); if (!(cause instanceof SQLException)) { throw e; } final int errorCode = ((SQLException) cause).getErrorCode(); if (errorCode == NUMERIC_VALUE_OUT_OF_RANGE_1 || errorCode == NUMERIC_VALUE_OUT_OF_RANGE_2 || errorCode == ErrorCode.SEQUENCE_EXHAUSTED || errorCode == ErrorCode.DUPLICATE_KEY_1) { if (super.getMessageCountInternal() >= Integer.MAX_VALUE) { throw new KuraStoreException("Table size is greater or equal than integer max value"); } final int freeId = super.connectionProvider.withPreparedStatement(this.sqlGetFreeId, (c, stmt) -> JdbcUtil.getFirstColumnValue(stmt::executeQuery, ResultSet::getInt), "failed to get free ID"); super.execute(this.sqlSetNextId, freeId); return; } throw e; } @Override protected synchronized long storeInternal(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException { final Timestamp now = new Timestamp(new Date().getTime()); return super.connectionProvider.withConnection(c -> { final long result; try (PreparedStatement pstmt = c.prepareStatement(super.queries.getSqlStore(), new String[] { "id" })) { pstmt.setString(1, topic); pstmt.setInt(2, qos); pstmt.setBoolean(3, retain); pstmt.setTimestamp(4, now, this.utcCalendar); pstmt.setTimestamp(5, null); pstmt.setInt(6, -1); pstmt.setTimestamp(7, null); if (payload == null || payload.length < PAYLOAD_BYTE_SIZE_THRESHOLD) { pstmt.setBytes(8, payload); pstmt.setNull(9, Types.BLOB); } else { pstmt.setNull(8, Types.VARBINARY); pstmt.setBinaryStream(9, new ByteArrayInputStream(payload), payload.length); } pstmt.setInt(10, priority); pstmt.setString(11, null); pstmt.setTimestamp(12, null); pstmt.execute(); result = (long) JdbcUtil.getFirstColumnValue(pstmt::getGeneratedKeys, ResultSet::getInt); } c.commit(); return result; }, "Cannot store message"); } @Override protected Builder buildStoredMessageBuilder(ResultSet rs, boolean includePayload) throws SQLException { StoredMessage.Builder result = super.buildStoredMessageBuilder(rs, false); if (includePayload) { byte[] payload = rs.getBytes("smallPayload"); if (payload == null) { payload = rs.getBytes("largePayload"); } result = result.withPayload(payload); } return result; } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbQueryableWireRecordStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import static java.util.Objects.isNull; import java.sql.Blob; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Optional; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.wire.store.AbstractJdbcQueryableWireRecordStoreImpl; @SuppressWarnings("restriction") public class H2DbQueryableWireRecordStoreImpl extends AbstractJdbcQueryableWireRecordStoreImpl { protected H2DbQueryableWireRecordStoreImpl(ConnectionProvider provider) { super(provider); } @Override protected Optional extractColumnValue(final ResultSet rset, final ResultSetMetaData rmet, final int i) throws SQLException { Object dbExtractedData = rset.getObject(i); if (isNull(dbExtractedData)) { return Optional.empty(); } if (dbExtractedData instanceof Blob) { final Blob dbExtractedBlob = (Blob) dbExtractedData; final int dbExtractedBlobLength = (int) dbExtractedBlob.length(); dbExtractedData = dbExtractedBlob.getBytes(1, dbExtractedBlobLength); } return Optional.of(dbExtractedData); } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServer.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.sql.SQLException; import java.util.Map; import org.eclipse.kura.configuration.ConfigurableComponent; import org.h2.tools.Server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class H2DbServer implements ConfigurableComponent { enum ServerType { WEB, TCP, PG } private static final Logger logger = LoggerFactory.getLogger(H2DbServer.class); private Server server; protected void activate(Map properties) { logger.info("activating..."); updated(properties); logger.info("activating...done"); } protected void updated(Map properties) { logger.info("updating..."); restartServer(new H2DbServerOptions(properties)); logger.info("updating...done"); } protected void deactivate() { logger.info("deactivating..."); shutdownServer(); logger.info("deactivating...done"); } private void restartServer(H2DbServerOptions configuration) { shutdownServer(); Server newServer = null; if (configuration.isServerEnabled()) { try { logger.info("Starting DB server..."); final String[] commandline = configuration.getServerCommandLine().split(" "); logger.debug("Server type: {}, commandline: {}", configuration.getServerType(), commandline); switch (configuration.getServerType()) { case TCP: newServer = Server.createTcpServer(commandline); break; case WEB: newServer = Server.createWebServer(commandline); break; case PG: newServer = Server.createPgServer(commandline); break; default: throw new IllegalArgumentException("Unknown server type"); } newServer.start(); this.server = newServer; logger.info("Starting DB server...done"); } catch (SQLException e) { logger.error("Failed to start server", e); shutdownServer(newServer); } } } private void shutdownServer() { shutdownServer(this.server); this.server = null; } private void shutdownServer(Server server) { if (server != null) { try { logger.info("Shutting down DB server..."); server.stop(); logger.info("Shutting down DB server...done"); } catch (Exception e) { logger.error("failed to shutdown DB server", e); } } } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServerOptions.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.util.Map; import org.eclipse.kura.internal.db.h2db.provider.H2DbServer.ServerType; class H2DbServerOptions { private static final String DB_SERVER_ENABLED_PROP_NAME = "db.server.enabled"; private static final String DB_SERVER_TYPE_PROP_NAME = "db.server.type"; private static final String DB_COMMAND_LINE_PROP_NAME = "db.server.commandline"; private static final Boolean DB_SERVER_ENABLED_DEFAULT = false; private static final String DB_SERVER_COMMAND_LINE_DEFAULT = "-tcpPort 9123 -tcpAllowOthers -ifExists"; private final Boolean isServerEnabled; private final ServerType serverType; private final String serverCommandLine; @SuppressWarnings("unchecked") private T getSafe(Object o, T defaultValue) { if (defaultValue.getClass().isInstance(o)) { return (T) o; } return defaultValue; } public H2DbServerOptions(Map properties) { this.isServerEnabled = getSafe(properties.get(DB_SERVER_ENABLED_PROP_NAME), DB_SERVER_ENABLED_DEFAULT); this.serverCommandLine = getSafe(properties.get(DB_COMMAND_LINE_PROP_NAME), DB_SERVER_COMMAND_LINE_DEFAULT); final String serverTypeString = (String) properties.getOrDefault(DB_SERVER_TYPE_PROP_NAME, "TCP"); if (ServerType.WEB.name().equals(serverTypeString)) { this.serverType = ServerType.WEB; } else if (ServerType.PG.name().equals(serverTypeString)) { this.serverType = ServerType.PG; } else { this.serverType = ServerType.TCP; } } public Boolean isServerEnabled() { return this.isServerEnabled; } public ServerType getServerType() { return this.serverType; } public String getServerCommandLine() { return this.serverCommandLine; } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.connection.listener.ConnectionListener; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.db.H2DbService; import org.eclipse.kura.message.store.provider.MessageStore; import org.eclipse.kura.message.store.provider.MessageStoreProvider; import org.eclipse.kura.util.jdbc.SQLFunction; import org.eclipse.kura.util.store.listener.ConnectionListenerManager; import org.eclipse.kura.wire.WireRecord; import org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider; import org.eclipse.kura.wire.store.provider.WireRecordStore; import org.eclipse.kura.wire.store.provider.WireRecordStoreProvider; import org.h2.jdbcx.JdbcConnectionPool; import org.h2.jdbcx.JdbcDataSource; import org.h2.tools.DeleteDbFiles; import org.osgi.service.component.ComponentException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class H2DbServiceImpl implements H2DbService, MessageStoreProvider, WireRecordStoreProvider, ConfigurableComponent, QueryableWireRecordStoreProvider { private static final String ANONYMOUS_MEM_INSTANCE_JDBC_URL = "jdbc:h2:mem:"; private static Map activeInstances = Collections.synchronizedMap(new HashMap<>()); private static final int MAX_LENGTH_INPLACE_LOB_VALUE = 2000000000; private static Logger logger = LoggerFactory.getLogger(H2DbServiceImpl.class); static { // load the driver // Use this way of loading the driver as it is required for OSGi // Just loading the class with Class.forName is not sufficient. try { DriverManager.registerDriver(new org.h2.Driver()); } catch (SQLException e) { throw new RuntimeException(e); } } private H2DbServiceOptions configuration; private JdbcDataSource dataSource; private JdbcConnectionPool connectionPool; private char[] lastSessionPassword = null; private CryptoService cryptoService; private ScheduledExecutorService executor; private ScheduledFuture checkpointTask; private ScheduledFuture defragTask; private final ReadWriteLock rwLock = new ReentrantReadWriteLock(true); private final AtomicInteger pendingUpdates = new AtomicInteger(); private final ThreadLocal isOnExecutor = ThreadLocal.withInitial(() -> false); private ConnectionListenerManager listenerManager = new ConnectionListenerManager(); private final ThreadPoolExecutor executorService = new ThreadPoolExecutor(0, 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); // ---------------------------------------------------------------- // // Dependencies // // ---------------------------------------------------------------- public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void unsetCryptoService(CryptoService cryptoService) { if (this.cryptoService.equals(cryptoService)) { this.cryptoService = null; } } // ---------------------------------------------------------------- // // Activation APIs // // ---------------------------------------------------------------- public void activate(final Map properties) { logger.info("activating..."); final String kuraServicePid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID); final ThreadFactory defaultFactory = this.executorService.getThreadFactory(); final AtomicInteger threadNumber = new AtomicInteger(); this.executorService.setThreadFactory(r -> { final Thread result = defaultFactory.newThread(() -> { this.isOnExecutor.set(true); r.run(); }); result.setName("H2DbService_" + kuraServicePid + "_" + threadNumber.getAndIncrement()); return result; }); this.executor = Executors.newSingleThreadScheduledExecutor(); updated(properties); logger.info("activating...done"); } public void updated(Map properties) { this.pendingUpdates.incrementAndGet(); this.executor.submit(() -> updateInternal(properties)); } public void deactivate() { logger.info("deactivate..."); this.executor.shutdown(); try { this.executor.awaitTermination(1, TimeUnit.MINUTES); } catch (InterruptedException e1) { logger.warn("Interrupted while waiting for db shutdown"); Thread.currentThread().interrupt(); } this.isOnExecutor.remove(); this.executorService.shutdown(); awaitExecutorServiceTermination(); try { shutdownDb(); } catch (SQLException e) { logger.warn("got exception while shutting down the database", e); } this.listenerManager.shutdown(); logger.info("deactivate...done"); } // ---------------------------------------------------------------- // // Service APIs // // ---------------------------------------------------------------- @Override public Connection getConnection() throws SQLException { if (this.pendingUpdates.get() > 0) { syncWithExecutor(); } final Lock lock = this.rwLock.readLock(); lock.lock(); try { return getConnectionInternal(); } finally { lock.unlock(); } } private T withConnectionInternal(ConnectionCallable callable) throws SQLException { final Lock executorlock = this.rwLock.readLock(); executorlock.lock(); Connection connection = null; try { connection = getConnectionInternal(); return callable.call(connection); } catch (final SQLException e) { logger.warn("Db operation failed"); rollback(connection); throw e; } finally { close(connection); executorlock.unlock(); } } @Override public T withConnection(ConnectionCallable callable) throws SQLException { if (this.pendingUpdates.get() > 0) { syncWithExecutor(); } if (Boolean.TRUE.equals(this.isOnExecutor.get())) { return withConnectionInternal(callable); } final Future result = this.executorService.submit(() -> withConnectionInternal(callable)); try { return result.get(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new SQLException(e); } catch (ExecutionException e) { if (e.getCause() instanceof SQLException) { throw (SQLException) e.getCause(); } else if (e.getCause() instanceof RuntimeException) { throw (RuntimeException) e.getCause(); } throw new IllegalStateException(e); } } @Override public void rollback(Connection conn) { try { if (conn != null) { conn.rollback(); } } catch (SQLException e) { logger.error("Error during Connection rollback.", e); } } @Override public void close(ResultSet... rss) { if (rss != null) { for (ResultSet rs : rss) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { logger.error("Error during ResultSet closing", e); } } } } @Override public void close(Statement... stmts) { if (stmts != null) { for (Statement stmt : stmts) { try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { logger.error("Error during Statement closing", e); } } } } @Override public void close(Connection conn) { try { if (conn != null) { conn.close(); } } catch (SQLException e) { logger.error("Error during Connection closing", e); } } // ---------------------------------------------------------------- // // Private methods // // ---------------------------------------------------------------- private void updateInternal(final Map properties) { final Lock lock = this.rwLock.writeLock(); lock.lock(); try { logger.info("updating..."); H2DbServiceOptions newConfiguration = new H2DbServiceOptions(properties); shutdownIfUrlOrUserChanged(newConfiguration); if (newConfiguration.isRemote()) { throw new IllegalArgumentException("Remote databases are not supported"); } final String baseUrl = newConfiguration.getBaseUrl(); if (baseUrl.equals(ANONYMOUS_MEM_INSTANCE_JDBC_URL)) { throw new IllegalArgumentException("Anonymous in-memory databases instances are not supported"); } if (isManagedByAnotherInstance(baseUrl)) { throw new IllegalStateException("Another H2DbService instance is managing the same DB URL," + " please change the DB URL or deactivate the other instance"); } final char[] passwordFromConfig = newConfiguration.getEncryptedPassword(); final char[] password = this.lastSessionPassword != null ? this.lastSessionPassword : passwordFromConfig; if (this.connectionPool == null) { openConnectionPool(newConfiguration, decryptPassword(password)); this.lastSessionPassword = password; } setParameters(newConfiguration); if (!newConfiguration.isZipBased() && !Arrays.equals(password, passwordFromConfig)) { final String decryptedPassword = decryptPassword(passwordFromConfig); changePassword(newConfiguration.getUser(), decryptedPassword); this.dataSource.setPassword(decryptedPassword); this.lastSessionPassword = passwordFromConfig; } if (newConfiguration.isFileBased()) { restartCheckpointTask(newConfiguration); restartDefragTask(newConfiguration); } if (this.configuration == null || newConfiguration.getConnectionPoolMaxSize() != this.configuration.getConnectionPoolMaxSize()) { this.executorService.setMaximumPoolSize(newConfiguration.getConnectionPoolMaxSize()); } this.configuration = newConfiguration; activeInstances.put(baseUrl, this); logger.info("updating...done"); } catch (Exception e) { try { shutdownDb(); } catch (SQLException sqlException) { disposeConnectionPool(); } stopCheckpointTask(); logger.error("Database initialization failed", e); } finally { lock.unlock(); this.pendingUpdates.decrementAndGet(); } } private void shutdownIfUrlOrUserChanged(H2DbServiceOptions newConfiguration) throws SQLException { if (this.configuration != null) { final boolean urlChanged = !this.configuration.getDbUrl().equals(newConfiguration.getDbUrl()); final boolean userChanged = !this.configuration.getUser().equalsIgnoreCase(newConfiguration.getUser()); if (urlChanged || userChanged) { shutdownDb(); } } } private void awaitExecutorServiceTermination() { try { this.executorService.awaitTermination(1, TimeUnit.MINUTES); } catch (InterruptedException e1) { logger.warn("Interrupted while waiting for db shutdown"); Thread.currentThread().interrupt(); } } private void setParameters(H2DbServiceOptions configuration) throws SQLException { if (!configuration.isFileBasedLogLevelSpecified()) { executeInternal("SET TRACE_LEVEL_FILE 0"); } // Set the maximum length for which a lob is created inline, regardless of the // connection string. if (configuration.isInMemory()) { executeInternal("SET MAX_LENGTH_INPLACE_LOB " + MAX_LENGTH_INPLACE_LOB_VALUE); } this.connectionPool.setMaxConnections(configuration.getConnectionPoolMaxSize()); } private void syncWithExecutor() { try { this.executor.submit(() -> { }).get(); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); throw new IllegalStateException(e); } catch (final Exception e1) { throw new IllegalStateException(e1); } } private Connection getConnectionInternal() throws SQLException { if (this.connectionPool == null) { throw new SQLException("Database instance not initialized"); } Connection conn = null; try { conn = this.connectionPool.getConnection(); } catch (SQLException e) { logger.error("Error getting connection", e); this.listenerManager.dispatchDisconnected(); throw new SQLException("Error getting connection"); } return conn; } private void executeInternal(String sql) throws SQLException { Connection conn = null; Statement stmt = null; try { conn = getConnectionInternal(); stmt = conn.createStatement(); stmt.execute(sql); conn.commit(); } catch (SQLException e) { rollback(conn); throw e; } finally { close(stmt); close(conn); } } private void shutdownDb() throws SQLException { this.lastSessionPassword = null; if (this.connectionPool == null) { return; } stopDefragTask(); stopCheckpointTask(); Connection conn = null; Statement stmt = null; try { conn = this.dataSource.getConnection(); stmt = conn.createStatement(); stmt.execute("SHUTDOWN"); } finally { close(stmt); close(conn); } disposeConnectionPool(); this.listenerManager.dispatchDisconnected(); activeInstances.remove(this.configuration.getBaseUrl()); } private void openConnectionPool(H2DbServiceOptions configuration, String password) { logger.info("Opening database with url: {}", configuration.getDbUrl()); this.dataSource = new JdbcDataSource(); this.dataSource.setURL(configuration.getDbUrl()); this.dataSource.setUser(configuration.getUser()); this.dataSource.setPassword(password); this.connectionPool = JdbcConnectionPool.create(this.dataSource); openDatabase(configuration, true); } private void openDatabase(H2DbServiceOptions configuration, boolean deleteDbOnError) { Connection conn = null; try { conn = getConnectionInternal(); this.listenerManager.dispatchConnected(); } catch (SQLException e) { logger.error("Failed to open database", e); if (deleteDbOnError && configuration.isFileBased()) { logger.warn("Deleting database files..."); deleteDbFiles(configuration); logger.warn("Deleting database files...done"); openDatabase(configuration, false); } else { disposeConnectionPool(); throw new ComponentException(e); } } finally { close(conn); } } private void deleteDbFiles(H2DbServiceOptions configuration) { try { final String directory = configuration.getDbDirectory(); final String dbName = configuration.getDatabaseName(); if (directory == null || dbName == null) { logger.warn("Failed to determine database directory or name, not deleting db"); return; } DeleteDbFiles.execute(directory, dbName, false); } catch (Exception e) { logger.warn("Failed to remove DB files", e); } } private void disposeConnectionPool() { if (this.connectionPool != null) { this.connectionPool.dispose(); this.connectionPool = null; } } private String decryptPassword(char[] encryptedPassword) throws KuraException { final char[] decodedPasswordChars = this.cryptoService.decryptAes(encryptedPassword); return new String(decodedPasswordChars); } private void changePassword(String user, String newPassword) throws SQLException { executeInternal("ALTER USER " + user + " SET PASSWORD '" + newPassword + "'"); } private boolean isManagedByAnotherInstance(String baseUrl) { final H2DbServiceImpl owner = activeInstances.get(baseUrl); return owner != null && owner != this; } private void restartCheckpointTask(final H2DbServiceOptions config) { stopCheckpointTask(); final long delaySeconds = config.getCheckpointIntervalSeconds(); if (delaySeconds <= 0) { return; } this.checkpointTask = this.executor.scheduleWithFixedDelay(new CheckpointTask(), delaySeconds, delaySeconds, TimeUnit.SECONDS); } private void stopCheckpointTask() { if (this.checkpointTask != null) { this.checkpointTask.cancel(false); this.checkpointTask = null; } } private void restartDefragTask(final H2DbServiceOptions config) { stopDefragTask(); final long delayMinutes = config.getDefragIntervalMinutes(); if (delayMinutes <= 0) { return; } this.checkpointTask = this.executor.scheduleWithFixedDelay(new DefragTask(config), delayMinutes, delayMinutes, TimeUnit.MINUTES); } private void stopDefragTask() { if (this.defragTask != null) { this.defragTask.cancel(false); this.defragTask = null; } } private class CheckpointTask implements Runnable { @Override public void run() { try { logger.info("performing checkpoint..."); executeInternal("CHECKPOINT SYNC"); logger.info("performing checkpoint...done"); } catch (final SQLException e) { logger.error("checkpoint failed", e); } } } private class DefragTask implements Runnable { private final H2DbServiceOptions configuration; public DefragTask(final H2DbServiceOptions configuration) { this.configuration = configuration; } private void shutdownDefrag() throws SQLException { Connection conn = null; Statement stmt = null; try { conn = H2DbServiceImpl.this.dataSource.getConnection(); stmt = conn.createStatement(); stmt.execute("SHUTDOWN DEFRAG"); } finally { close(stmt); close(conn); } } @Override public void run() { final Lock lock = H2DbServiceImpl.this.rwLock.writeLock(); lock.lock(); try { logger.info("shutting down and defragmenting db..."); shutdownDefrag(); disposeConnectionPool(); final String password = decryptPassword(this.configuration.getEncryptedPassword()); openConnectionPool(this.configuration, password); logger.info("shutting down and defragmenting db...done"); } catch (final Exception e) { logger.error("failed to shutdown and defrag db", e); } finally { lock.unlock(); } } } @Override public MessageStore openMessageStore(String name) throws KuraStoreException { return new H2DbMessageStoreImpl(this::withConnectionAdapter, name); } @Override public WireRecordStore openWireRecordStore(String name) throws KuraStoreException { return new H2DbWireRecordStoreImpl(this::withConnectionAdapter, name); } @Override public List performQuery(String query) throws KuraStoreException { return new H2DbQueryableWireRecordStoreImpl(this::withConnectionAdapter).performQuery(query); } @SuppressWarnings("restriction") private T withConnectionAdapter(final SQLFunction callable) throws SQLException { return this.withConnection(callable::call); } @Override public void addListener(ConnectionListener listener) { this.listenerManager.add(listener); } @Override public void removeListener(ConnectionListener listener) { this.listenerManager.remove(listener); } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.io.File; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; class H2DbServiceOptions { private static final Property CONNECTOR_URL_PROP = new Property<>("db.connector.url", "jdbc:h2:mem:kuradb"); private static final Property USER_PROP = new Property<>("db.user", "SA"); private static final Property PASSWORD_PROP = new Property<>("db.password", ""); private static final Property CHECKPOINT_INTERVAL_SECONDS_PROP = new Property<>( "db.checkpoint.interval.seconds", 900); private static final Property DEFRAG_INTERVAL_MINUTES_PROP = new Property<>("db.defrag.interval.minutes", 20); private static final Property CONNECTION_POOL_MAX_SIZE = new Property<>("db.connection.pool.max.size", 10); private static final Pattern FILE_LOG_LEVEL_PATTERN = generatePatternForProperty("trace_level_file"); private static final Pattern USER_PATTERN = generatePatternForProperty("user"); private static final Pattern PASSWORD_PATTERN = generatePatternForProperty("password"); private static final Pattern JDBC_URL_PARSE_PATTERN = Pattern.compile("jdbc:([^:]+):(([^:]+):)?([^;]*)(;.*)?"); private final String dbUrl; private final String user; private final char[] password; private final long checkpointIntervalSeconds; private final long defragIntervalMinutes; private final int maxConnectionPoolSize; private boolean isInMemory; private boolean isFileBased; private boolean isZipBased; private boolean isRemote; private boolean isFileBasedLogLevelSpecified; private String baseUrl; private String dbDirectory; private String dbName; public H2DbServiceOptions(Map properties) { this.password = PASSWORD_PROP.get(properties).toCharArray(); this.user = USER_PROP.get(properties); this.checkpointIntervalSeconds = CHECKPOINT_INTERVAL_SECONDS_PROP.get(properties); this.defragIntervalMinutes = DEFRAG_INTERVAL_MINUTES_PROP.get(properties); this.maxConnectionPoolSize = CONNECTION_POOL_MAX_SIZE.get(properties); String dbUrlProp = CONNECTOR_URL_PROP.get(properties); dbUrlProp = USER_PATTERN.matcher(dbUrlProp).replaceAll(""); dbUrlProp = PASSWORD_PATTERN.matcher(dbUrlProp).replaceAll(""); this.dbUrl = dbUrlProp; computeUrlParts(); } private static Pattern generatePatternForProperty(String property) { StringBuilder patternStringBuilder = new StringBuilder(); patternStringBuilder.append(';'); for (int i = 0; i < property.length(); i++) { final char c = property.charAt(i); patternStringBuilder.append('[').append(Character.toLowerCase(c)).append(Character.toUpperCase(c)) .append(']'); } patternStringBuilder.append("=[^;]*"); return Pattern.compile(patternStringBuilder.toString()); } private void computeUrlParts() { final Matcher jdbcUrlMatcher = JDBC_URL_PARSE_PATTERN.matcher(this.dbUrl); if (!jdbcUrlMatcher.matches()) { throw new IllegalArgumentException("Invalid DB URL"); } String driver = jdbcUrlMatcher.group(1); if (driver == null || !"h2".equals(driver)) { throw new IllegalArgumentException("JDBC driver must be h2"); } String protocol = jdbcUrlMatcher.group(3); String url = jdbcUrlMatcher.group(4); if (protocol == null && ".".equals(url)) { // jdbc:h2:. is a shorthand for jdbc:h2:mem: protocol = "mem"; url = ""; } else { if (protocol == null) { protocol = "file"; } if (url == null) { url = ""; } } parseProtocol(protocol); this.baseUrl = "jdbc:h2:" + protocol + ':' + url; if (this.isFileBased) { File file = new File(url); this.dbDirectory = file.getParent(); if (this.dbDirectory == null) { this.dbDirectory = "."; } this.dbName = file.getName(); } this.isFileBasedLogLevelSpecified = FILE_LOG_LEVEL_PATTERN.matcher(this.dbUrl).find(); } private void parseProtocol(String protocol) { if ("mem".equals(protocol)) { this.isInMemory = true; } else if ("file".equals(protocol)) { this.isFileBased = true; } else if ("zip".equals(protocol)) { this.isZipBased = true; } else { this.isRemote = true; } } public String getDbUrl() { return this.dbUrl; } public boolean isFileBased() { return this.isFileBased; } public boolean isInMemory() { return this.isInMemory; } public boolean isZipBased() { return this.isZipBased; } public boolean isRemote() { return this.isRemote; } public String getDbDirectory() { return this.dbDirectory; } public String getDatabaseName() { return this.dbName; } public long getCheckpointIntervalSeconds() { return this.checkpointIntervalSeconds; } public long getDefragIntervalMinutes() { return this.defragIntervalMinutes; } public String getBaseUrl() { return this.baseUrl; } public String getUser() { return this.user; } public char[] getEncryptedPassword() { return this.password; } public int getConnectionPoolMaxSize() { return this.maxConnectionPoolSize; } public boolean isFileBasedLogLevelSpecified() { return this.isFileBasedLogLevelSpecified; } private static class Property { private final String key; private final T defaultValue; public Property(String key, T defaultValue) { this.key = key; this.defaultValue = defaultValue; } @SuppressWarnings("unchecked") public T get(Map properties) { final Object value = properties.get(this.key); if (this.defaultValue.getClass().isInstance(value)) { return (T) value; } return this.defaultValue; } } } ================================================ FILE: kura/org.eclipse.kura.db.h2db.provider/src/main/java/org/eclipse/kura/internal/db/h2db/provider/H2DbWireRecordStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023, 2024 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech ******************************************************************************/ package org.eclipse.kura.internal.db.h2db.provider; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.type.BooleanValue; import org.eclipse.kura.type.ByteArrayValue; import org.eclipse.kura.type.DataType; import org.eclipse.kura.type.DoubleValue; import org.eclipse.kura.type.FloatValue; import org.eclipse.kura.type.IntegerValue; import org.eclipse.kura.type.LongValue; import org.eclipse.kura.type.StringValue; import org.eclipse.kura.type.TypedValue; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.wire.store.AbstractJdbcWireRecordStoreImpl; import org.eclipse.kura.util.wire.store.JdbcWireRecordStoreQueries; @SuppressWarnings("restriction") public class H2DbWireRecordStoreImpl extends AbstractJdbcWireRecordStoreImpl { private static final Map>, String> TYPE_MAPPING = buildTypeMapping(); public H2DbWireRecordStoreImpl(final ConnectionProvider provider, final String tableName) throws KuraStoreException { super(provider, tableName); super.createTable(); super.createTimestampIndex(); } @Override protected JdbcWireRecordStoreQueries buildSqlWireRecordStoreQueries() { return JdbcWireRecordStoreQueries.builder() .withSqlAddColumn("ALTER TABLE " + super.escapedTableName + " ADD COLUMN {0} {1};") .withSqlCreateTable( "CREATE TABLE IF NOT EXISTS " + super.escapedTableName + " (ID BIGINT GENERATED BY DEFAULT " + "AS IDENTITY(START WITH 1 INCREMENT BY 1) PRIMARY KEY, TIMESTAMP BIGINT);") .withSqlRowCount("SELECT COUNT(*) FROM " + super.escapedTableName + ";") .withSqlDeleteRangeTable("DELETE FROM " + super.escapedTableName + " WHERE ID IN (SELECT ID FROM " + super.escapedTableName + " ORDER BY ID ASC LIMIT {0});") .withSqlDropColumn("ALTER TABLE " + super.escapedTableName + " DROP COLUMN {0};") .withSqlInsertRecord("INSERT INTO " + super.escapedTableName + " ({0}) VALUES ({1});") .withSqlTruncateTable("TRUNCATE TABLE " + super.escapedTableName + ";") .withSqlCreateTimestampIndex( "CREATE INDEX IF NOT EXISTS " + super.escapeIdentifier(tableName + "_TIMESTAMP") + " ON " + super.escapedTableName + " (TIMESTAMP DESC);") .build(); } @Override protected Optional getMappedSqlType(final TypedValue value) { return Optional.ofNullable(value).flatMap(v -> Optional.ofNullable(TYPE_MAPPING.get(v.getClass()))); } private static Map>, String> buildTypeMapping() { final Map>, String> result = new HashMap<>(); result.put(StringValue.class, "VARCHAR(102400)"); result.put(IntegerValue.class, "INTEGER"); result.put(LongValue.class, "BIGINT"); result.put(BooleanValue.class, "BOOLEAN"); result.put(DoubleValue.class, "DOUBLE"); result.put(FloatValue.class, "FLOAT"); result.put(ByteArrayValue.class, "BLOB"); return Collections.unmodifiableMap(result); } @Override protected boolean isCorrectColumnType(final TypedValue value, String mappedType, String actualType) { final boolean mappedTypeEquals = Objects.equals(mappedType, actualType); if (mappedTypeEquals) { return true; } final DataType dataType = value.getType(); if (dataType == DataType.DOUBLE || dataType == DataType.FLOAT) { return "DOUBLE PRECISION".equals(actualType) || actualType.startsWith("FLOAT"); } else if (dataType == DataType.STRING) { return actualType.startsWith("CHARACTER VARYING"); } else if (dataType == DataType.BYTE_ARRAY) { return "BINARY LARGE OBJECT".equals(actualType); } else { return false; } } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/.gitignore ================================================ lib/ ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.db.sqlite.provider Bundle-SymbolicName: org.eclipse.kura.db.sqlite.provider;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ClassPath: . Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.kura.internal.db.sqlite.provider.SqliteProviderActivator Import-Package: com.zaxxer.hikari;version="2.7.9", org.eclipse.kura;version="[1.7,2.0)", org.eclipse.kura.configuration;version="[1.2,2.0)", org.eclipse.kura.connection.listener;version="1.0.0", org.eclipse.kura.crypto;version="1.3.0", org.eclipse.kura.data;version="[1.1,2.0)", org.eclipse.kura.db;version="[2.0,2.1)", org.eclipse.kura.message.store;version="[1.0,2.0)", org.eclipse.kura.message.store.provider;version="[1.0,1.1)", org.eclipse.kura.type;version="[1.1,2.0)", org.eclipse.kura.util.configuration;version="[1.0,1.1)", org.eclipse.kura.util.jdbc;version="[1.0,2.0)", org.eclipse.kura.util.message.store;version="[1.0,2.0)", org.eclipse.kura.util.store.listener;version="[1.0,2.0)", org.eclipse.kura.util.wire.store;version="[1.0,1.1)", org.eclipse.kura.wire;version="[2.0,3.0)", org.eclipse.kura.wire.store.provider;version="[1.0,1.1)", org.osgi.framework;version="1.10.0", org.osgi.service.component;version="1.4.0", org.slf4j;version="1.7.32", org.sqlite;version="3.39.3.0", org.sqlite.core;version="3.39.3.0", org.sqlite.date;version="3.39.3.0", org.sqlite.javax;version="3.39.3.0", org.sqlite.jdbc3;version="3.39.3.0", org.sqlite.jdbc4;version="3.39.3.0", org.sqlite.util;version="3.39.3.0" ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/metatype/org.eclipse.kura.db.SQLiteDbService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/org.eclipse.kura.db.SQLiteDbService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/OSGI-INF/org.eclipse.kura.internal.db.sqlite.provider.SqliteDebugShell.xml ================================================ executeQuery ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/build.properties ================================================ # # Copyright (c) 2022 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about_files/,\ about.html src.includes = about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.db.sqlite.provider 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/ConnectionPoolManager.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.sql.Connection; import java.sql.SQLException; import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariPoolMXBean; public class ConnectionPoolManager { private static final Logger logger = LoggerFactory.getLogger(ConnectionPoolManager.class); private static final Long ACTIVE_CONNECTION_WAIT_TIMEOUT = 30000L; private HikariDataSource hikariDatasource; private SQLiteDataSource sqliteDataSource; public ConnectionPoolManager(final SQLiteDataSource sqliteDataSource, final int maxConnectionCount) { HikariConfig config = new HikariConfig(); config.setDataSource(sqliteDataSource); config.setMaximumPoolSize(maxConnectionCount); config.setConnectionTimeout(ACTIVE_CONNECTION_WAIT_TIMEOUT); config.setAllowPoolSuspension(true); config.setIdleTimeout(0); config.setMaxLifetime(0); this.sqliteDataSource = sqliteDataSource; this.hikariDatasource = new HikariDataSource(config); } public Connection getConnection() throws SQLException { logger.debug("getting connection"); return this.hikariDatasource.getConnection(); } void withExclusiveConnection(final Consumer consumer) { HikariPoolMXBean hikariPoolMXBean = this.hikariDatasource.getHikariPoolMXBean(); waitNoActiveConnections(hikariPoolMXBean, Optional.empty()); try { try (final Connection conn = this.sqliteDataSource.getConnection()) { consumer.accept(conn); } } catch (final Exception e) { logger.warn("Exception while running task with exclusive connection", e); } finally { hikariPoolMXBean.resumePool(); } } private void waitNoActiveConnections(HikariPoolMXBean hikariPoolMXBean, Optional timeoutMs) { hikariPoolMXBean.suspendPool(); waitCondition(() -> hikariPoolMXBean.getActiveConnections() <= 0, timeoutMs); } public void shutdown(final Optional waitIdleTimeoutMs) { HikariPoolMXBean hikariPoolMXBean = this.hikariDatasource.getHikariPoolMXBean(); if (waitIdleTimeoutMs.isPresent()) { waitNoActiveConnections(hikariPoolMXBean, waitIdleTimeoutMs); } if (hikariPoolMXBean.getActiveConnections() > 0) { logger.warn("Closing connection pool with {} active connections", hikariPoolMXBean.getActiveConnections()); } this.hikariDatasource.close(); } private boolean waitCondition(final BooleanSupplier condition, final Optional timeoutMs) { final long end = timeoutMs.map(t -> System.nanoTime() + TimeUnit.MILLISECONDS.toNanos(t)) .orElse(Long.MAX_VALUE); while (System.nanoTime() < end) { if (condition.getAsBoolean()) { return true; } try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } return false; } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/DatabaseLoader.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Optional; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeyFormat; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.EncryptionKeySpec; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.JournalMode; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.Mode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sqlite.SQLiteConfig; import org.sqlite.SQLiteDataSource; public class DatabaseLoader { private static final Logger logger = LoggerFactory.getLogger(DatabaseLoader.class); private final SqliteDbServiceOptions newOptions; private final Optional oldOptions; private final CryptoService cryptoService; public DatabaseLoader(final SqliteDbServiceOptions newOptions, final Optional oldOptions, final CryptoService cryptoService) { this.newOptions = newOptions; this.oldOptions = oldOptions; this.cryptoService = cryptoService; } public SQLiteDataSource openDataSource() throws SQLException, KuraException { try { return openDataSourceInternal(); } catch (final Exception e) { final boolean isConfigurationAttributeInvalidException = (e instanceof KuraException && ((KuraException) e).getCode() == KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID); if (this.newOptions.isDeleteDbFilesOnFailure() && this.newOptions.getMode() != Mode.IN_MEMORY && !isConfigurationAttributeInvalidException) { logger.warn("failed to open database, deleting database files and retrying", e); deleteDbFiles(newOptions.getPath()); return openDataSourceInternal(); } throw e; } } protected SQLiteDataSource openDataSourceInternal() throws SQLException, KuraException { final String dbUrl = this.newOptions.getDbUrl(); if (newOptions.getMode() != Mode.PERSISTED) { return openDataSource(dbUrl, Optional.empty(), Optional.empty()); } final List> applicableEncryptionKeys = new ArrayList<>(); final Optional keyFromNewOptions = this.newOptions.getEncryptionKey(cryptoService); addEncryptionKey(applicableEncryptionKeys, keyFromNewOptions, "key from new options"); if (this.oldOptions.isPresent()) { try { addEncryptionKey(applicableEncryptionKeys, this.oldOptions.get().getEncryptionKey(cryptoService), "key from old options"); } catch (final Exception e) { logger.warn("failed to get key from old options", e); } } addEncryptionKey(applicableEncryptionKeys, getCryptoServiceEntry(newOptions.getPath()), "key from CryptoService"); applicableEncryptionKeys.add(Optional.empty()); Exception lastException = null; final Optional journalMode = Optional.of(this.newOptions.getJournalMode()); for (final Optional encryptionKey : applicableEncryptionKeys) { try { SQLiteDataSource result = openDataSource(dbUrl, encryptionKey, journalMode); if (!encryptionKey.equals(keyFromNewOptions)) { changeEncryptionKey(result, keyFromNewOptions, newOptions); result = openDataSource(dbUrl, keyFromNewOptions, journalMode); } updateCryptoServiceEntry(newOptions.getPath(), keyFromNewOptions); return result; } catch (final Exception e) { logger.debug("database open attempt failed", e); lastException = e; // try next one } } throw new SQLException("Failed to open database", lastException); } private void addEncryptionKey(final List> applicableEncryptionKeys, final Optional keyFromNewOptions, final String type) { if (keyFromNewOptions.isPresent()) { logger.debug("adding {}", type); applicableEncryptionKeys.add(keyFromNewOptions); } } private void updateCryptoServiceEntry(final String dbPath, final Optional keyFromOptions) throws KuraException { final String entryKey = getCryptoServicePasswordEntryKey(dbPath); final char[] entryValue = encodeCrtpyoServicePasswordEntry(keyFromOptions).toCharArray(); final char[] currentValue = this.cryptoService.getKeyStorePassword(entryKey); if (!Arrays.equals(entryValue, currentValue)) { this.cryptoService.setKeyStorePassword(entryKey, entryValue); } } private String getCryptoServicePasswordEntryKey(final String dbPath) { return "sqlite:db:" + dbPath; } private String encodeCrtpyoServicePasswordEntry(final Optional encryptionKey) { if (encryptionKey.isPresent()) { return encryptionKey.get().getFormat().name() + ":" + encryptionKey.get().getKey(); } else { return ""; } } private Optional getCryptoServiceEntry(final String dbPath) { try { final String raw = new String( this.cryptoService.getKeyStorePassword(getCryptoServicePasswordEntryKey(dbPath))); final int index = raw.indexOf(':'); final EncryptionKeyFormat format = EncryptionKeyFormat.valueOf(raw.substring(0, index)); final String key = raw.substring(index + 1); return Optional.of(new EncryptionKeySpec(key, format)); } catch (final Exception e) { return Optional.empty(); } } protected SQLiteDataSource openDataSource(final String url, final Optional encryptionKey, final Optional journalMode) throws SQLException { final SQLiteConfig config = new SQLiteConfig(); if (encryptionKey.isPresent()) { config.setPragma(SQLiteConfig.Pragma.PASSWORD, encryptionKey.get().getKey()); config.setHexKeyMode(encryptionKey.get().getFormat().toHexKeyMode()); } if (journalMode.isPresent()) { config.setJournalMode(journalMode.get() == JournalMode.ROLLBACK_JOURNAL ? SQLiteConfig.JournalMode.DELETE : SQLiteConfig.JournalMode.WAL); } final SQLiteDataSource dataSource = buildDataSource(config); dataSource.setUrl(url); dataSource.getConnection().close(); return dataSource; } protected void changeEncryptionKey(final SQLiteDataSource dataSource, final Optional encryptionKey, final SqliteDbServiceOptions options) throws SQLException { logger.info("Updating encryption key for {}", dataSource.getUrl()); try (final Connection connection = dataSource.getConnection()) { if (encryptionKey.isPresent()) { final EncryptionKeySpec encryptionKeySpec = encryptionKey.get(); final String key = encryptionKey.get().getKey().replace("'", "''"); if (encryptionKeySpec.getFormat() == EncryptionKeyFormat.HEX_SQLCIPHER) { executeQuery(connection, "PRAGMA rekey = \"x'" + key + "'\";"); } else if (encryptionKeySpec.getFormat() == EncryptionKeyFormat.HEX_SSE) { executeQuery(connection, "PRAGMA hexrekey = '" + key + "';"); } else { executeQuery(connection, "PRAGMA rekey = '" + key + "';"); } } else { executeQuery(connection, "PRAGMA rekey = '';"); } SqliteUtil.vacuum(connection, options); } } protected void deleteDbFiles(final String dbPath) { final List paths = Arrays.asList(dbPath, dbPath + "-wal", dbPath + "-journal", dbPath + "-shm"); for (final String path : paths) { try { deleteFile(new File(path)); } catch (final Exception e) { logger.warn("failed to delete database file", e); } } } protected void executeQuery(final Connection connection, final String query) throws SQLException { try (final Statement stmt = connection.createStatement()) { stmt.execute(query); } } protected SQLiteDataSource buildDataSource(final SQLiteConfig config) { return new SQLiteDataSource(config); } protected void deleteFile(final File file) throws IOException { if (file.exists()) { logger.info("deleting database file: {}", file.getAbsolutePath()); Files.delete(file.toPath()); } } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDbServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.connection.listener.ConnectionListener; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.db.BaseDbService; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.Mode; import org.eclipse.kura.message.store.provider.MessageStore; import org.eclipse.kura.message.store.provider.MessageStoreProvider; import org.eclipse.kura.util.jdbc.SQLFunction; import org.eclipse.kura.util.store.listener.ConnectionListenerManager; import org.eclipse.kura.wire.WireRecord; import org.eclipse.kura.wire.store.provider.QueryableWireRecordStoreProvider; import org.eclipse.kura.wire.store.provider.WireRecordStore; import org.eclipse.kura.wire.store.provider.WireRecordStoreProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sqlite.SQLiteDataSource; import org.sqlite.SQLiteJDBCLoader; public class SqliteDbServiceImpl implements BaseDbService, ConfigurableComponent, MessageStoreProvider, WireRecordStoreProvider, QueryableWireRecordStoreProvider { private static final Set OPEN_URLS = new HashSet<>(); private static final Logger logger = LoggerFactory.getLogger(SqliteDbServiceImpl.class); private CryptoService cryptoService; private SqliteDebugShell debugShell; private Optional state = Optional.empty(); private ConnectionListenerManager listenerManager = new ConnectionListenerManager(); public void setDebugShell(final SqliteDebugShell debugShell) { this.debugShell = debugShell; } public void setCryptoService(final CryptoService cryptoService) { this.cryptoService = cryptoService; } public void activate(final Map properties) { logger.info("activating..."); try { logger.info("SQLite driver is in native mode: {}", SQLiteJDBCLoader.isNativeMode()); } catch (Exception e) { logger.info("Failed to determine if SQLite driver is in native mode", e); } updated(properties); logger.info("activating...done"); } public synchronized void updated(final Map properties) { logger.info("updating..."); final SqliteDbServiceOptions newOptions = new SqliteDbServiceOptions(properties); this.debugShell.setPidAllowed(newOptions.getKuraServicePid(), newOptions.isDebugShellAccessEnabled()); final Optional oldOptions = this.state.map(DbState::getOptions); if (!oldOptions.equals(Optional.of(newOptions))) { shutdown(); try { this.state = Optional.of(new DbState(newOptions, oldOptions, cryptoService)); } catch (final Exception e) { logger.warn("Failed to initialize the database instance", e); } } logger.info("updating...done"); } public synchronized void deactivate() { logger.info("deactivating..."); shutdown(); logger.info("deactivating...done"); } private void shutdown() { if (this.state.isPresent()) { this.state.get().shutdown(); this.state = Optional.empty(); this.listenerManager.dispatchDisconnected(); } } @Override public synchronized Connection getConnection() throws SQLException { if (this.state.isPresent()) { Connection connection; try { connection = this.state.get().getConnection(); } catch (SQLException e) { this.listenerManager.dispatchDisconnected(); throw e; } return connection; } else { this.listenerManager.dispatchDisconnected(); throw new SQLException("Database is not initialized"); } } private class DbState { private final Optional executor; private final ConnectionPoolManager connectionPool; private final SqliteDbServiceOptions options; public DbState(SqliteDbServiceOptions options, final Optional oldOptions, final CryptoService cryptoService) throws SQLException, KuraException { this.options = options; tryClaimFile(); try { logger.info("opening database with url: {}...", options.getDbUrl()); final SQLiteDataSource dataSource = new DatabaseLoader(options, oldOptions, cryptoService) .openDataSource(); int maxConnectionCount = options.getMode() == Mode.PERSISTED ? options.getConnectionPoolMaxSize() : 1; this.connectionPool = new ConnectionPoolManager(dataSource, maxConnectionCount); if (options.isPeriodicDefragEnabled() || options.isPeriodicWalCheckpointEnabled()) { this.executor = Optional.of(Executors.newSingleThreadScheduledExecutor()); } else { this.executor = Optional.empty(); } if (options.isPeriodicDefragEnabled()) { this.executor.get().scheduleWithFixedDelay(this::defrag, options.getDefragIntervalSeconds(), options.getDefragIntervalSeconds(), TimeUnit.SECONDS); } if (options.isPeriodicWalCheckpointEnabled()) { this.executor.get().scheduleWithFixedDelay(this::walCheckpoint, options.getWalCheckpointIntervalSeconds(), options.getWalCheckpointIntervalSeconds(), TimeUnit.SECONDS); } logger.info("opening database with url: {}...done", options.getDbUrl()); SqliteDbServiceImpl.this.listenerManager.dispatchConnected(); } catch (final Exception e) { releaseFile(); throw e; } } public SqliteDbServiceOptions getOptions() { return this.options; } public Connection getConnection() throws SQLException { return this.connectionPool.getConnection(); } private void walCheckpoint() { try (final Connection connection = getConnection()) { SqliteUtil.walCeckpoint(connection, options); } catch (Exception e) { logger.warn("failed to close connection", e); } } private void defrag() { this.connectionPool.withExclusiveConnection(conn -> SqliteUtil.vacuum(conn, options)); } private void tryClaimFile() { if (options.getMode() != Mode.PERSISTED) { return; } synchronized (OPEN_URLS) { if (OPEN_URLS.contains(options.getPath())) { throw new IllegalStateException("Another database instance is managing the same database file"); } OPEN_URLS.add(options.getPath()); } } private void releaseFile() { if (options.getMode() != Mode.PERSISTED) { return; } synchronized (OPEN_URLS) { OPEN_URLS.remove(options.getPath()); } } public void shutdown() { try { if (this.executor.isPresent()) { this.executor.get().shutdown(); try { this.executor.get().awaitTermination(120, TimeUnit.SECONDS); } catch (final InterruptedException e) { logger.warn("Interrupted while waiting for executor shutdown"); Thread.currentThread().interrupt(); } } logger.info("closing database with url: {}...", options.getDbUrl()); this.connectionPool.shutdown(Optional.of(120 * 1000L)); logger.info("closing database with url: {}...done", options.getDbUrl()); } finally { releaseFile(); } } } @Override public void rollback(Connection conn) { try { if (conn != null) { conn.rollback(); } } catch (SQLException e) { logger.error("Error during Connection rollback.", e); } } @Override public void close(ResultSet... rss) { if (rss == null) { return; } for (ResultSet rs : rss) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { logger.error("Error during ResultSet closing", e); } } } @Override public void close(Statement... stmts) { if (stmts == null) { return; } for (Statement stmt : stmts) { try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { logger.error("Error during Statement closing", e); } } } @Override public void close(Connection conn) { try { if (conn != null) { conn.close(); } } catch (SQLException e) { logger.error("Error during Connection closing", e); } } @Override public MessageStore openMessageStore(String name) throws KuraStoreException { return new SqliteMessageStoreImpl(this::withConnection, name); } @Override public WireRecordStore openWireRecordStore(String name) throws KuraStoreException { return new SqliteWireRecordStoreImpl(this::withConnection, name); } @Override @SuppressWarnings("restriction") public List performQuery(String query) throws KuraStoreException { return new SqliteQueryableWireRecordStoreImpl(this::withConnection).performQuery(query); } @SuppressWarnings("restriction") private T withConnection(final SQLFunction callable) throws SQLException { try (final Connection conn = this.getConnection()) { return callable.call(conn); } } @Override public void addListener(ConnectionListener listener) { this.listenerManager.add(listener); } @Override public void removeListener(ConnectionListener listener) { this.listenerManager.remove(listener); } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDbServiceOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022, 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.regex.Pattern; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.util.configuration.Property; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sqlite.SQLiteConfig.HexKeyMode; class SqliteDbServiceOptions { private static final String ENCRYPTION_KEY = "Encryption Key"; private static final Logger logger = LoggerFactory.getLogger(SqliteDbServiceOptions.class); private static final Pattern HEX_PATTERN = Pattern.compile("[0-9a-fA-F]+"); public enum Mode { IN_MEMORY, PERSISTED } public enum JournalMode { ROLLBACK_JOURNAL, WAL } public enum EncryptionKeyFormat { ASCII, HEX_SSE, HEX_SQLCIPHER; public HexKeyMode toHexKeyMode() { if (this == EncryptionKeyFormat.ASCII) { return HexKeyMode.NONE; } else if (this == EncryptionKeyFormat.HEX_SSE) { return HexKeyMode.SSE; } else if (this == EncryptionKeyFormat.HEX_SQLCIPHER) { return HexKeyMode.SQLCIPHER; } else { throw new IllegalStateException(); } } } public static class EncryptionKeySpec { private final String key; private final EncryptionKeyFormat format; public EncryptionKeySpec(final String key, final EncryptionKeyFormat format) { this.key = key; this.format = format; } public String getKey() { return this.key; } public EncryptionKeyFormat getFormat() { return this.format; } @Override public int hashCode() { return Objects.hash(this.format, this.key); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof EncryptionKeySpec)) { return false; } EncryptionKeySpec other = (EncryptionKeySpec) obj; return this.format == other.format && Objects.equals(this.key, other.key); } } private static final Property MODE_PROPERTY = new Property<>("db.mode", Mode.IN_MEMORY.name()); private static final Property PATH_PROPERTY = new Property<>("db.path", "/opt/mydb.sqlite"); private static final Property CONNECTION_POOL_MAX_SIZE_PROPERTY = new Property<>( "db.connection.pool.max.size", 10); private static final Property JOURNAL_MODE_PROPERTY = new Property<>("db.journal.mode", JournalMode.WAL.name()); private static final Property DEFRAG_ENABLED_PROPERTY = new Property<>("db.defrag.enabled", true); private static final Property DEFRAG_INTERVAL_SECONDS_PROPERTY = new Property<>("db.defrag.interval.seconds", 900L); private static final Property WAL_CHECHPOINT_ENABLED_PROPERTY = new Property<>("db.wal.checkpoint.enabled", true); private static final Property WAL_CHECKPOINT_INTERVAL_SECONDS_PROPERTY = new Property<>( "db.wal.checkpoint.interval.seconds", 600L); private static final Property DEBUG_SHELL_ACCESS_ENABLED_PROPERTY = new Property<>( "debug.shell.access.enabled", false); private static final Property ENCRYPTION_KEY_PROPERTY = new Property<>("db.key", String.class); private static final Property ENCRYPTION_KEY_FORMAT_PROPERTY = new Property<>("db.key.format", EncryptionKeyFormat.ASCII.name()); private static final Property DELETE_DB_FILES_ON_FAILURE = new Property<>("delete.db.files.on.failure", true); private static final Property KURA_SERVICE_PID_PROPERTY = new Property<>( ConfigurationService.KURA_SERVICE_PID, "sqlitedb"); private final Mode mode; private final String path; private final String kuraServicePid; private final boolean isDebugShellAccessEnabled; private final boolean defragEnabled; private final long defragIntervalSeconds; private final boolean walCheckpointEnabled; private final long walCheckpointIntervalSeconds; private final int maxConnectionPoolSize; private final JournalMode journalMode; private final Optional encryptionKey; private final EncryptionKeyFormat encryptionKeyFormat; private final boolean deleteDbFilesOnFailure; public SqliteDbServiceOptions(Map properties) { this.mode = extractMode(properties); this.path = sanitizePath(PATH_PROPERTY.get(properties)); this.kuraServicePid = KURA_SERVICE_PID_PROPERTY.get(properties); this.maxConnectionPoolSize = CONNECTION_POOL_MAX_SIZE_PROPERTY.get(properties); this.defragEnabled = DEFRAG_ENABLED_PROPERTY.get(properties); this.defragIntervalSeconds = DEFRAG_INTERVAL_SECONDS_PROPERTY.get(properties); this.walCheckpointEnabled = WAL_CHECHPOINT_ENABLED_PROPERTY.get(properties); this.walCheckpointIntervalSeconds = WAL_CHECKPOINT_INTERVAL_SECONDS_PROPERTY.get(properties); this.journalMode = extractJournalMode(properties); this.isDebugShellAccessEnabled = DEBUG_SHELL_ACCESS_ENABLED_PROPERTY.get(properties); this.encryptionKey = ENCRYPTION_KEY_PROPERTY.getOptional(properties).filter(s -> !s.trim().isEmpty()); this.encryptionKeyFormat = extractEncryptionKeyFormat(properties); this.deleteDbFilesOnFailure = DELETE_DB_FILES_ON_FAILURE.get(properties); } public Mode getMode() { return this.mode; } public String getPath() { return this.path; } public int getConnectionPoolMaxSize() { return this.maxConnectionPoolSize; } public boolean isDebugShellAccessEnabled() { return this.isDebugShellAccessEnabled; } public long getDefragIntervalSeconds() { return this.defragIntervalSeconds; } public JournalMode getJournalMode() { return this.journalMode; } public String getKuraServicePid() { return this.kuraServicePid; } public long getWalCheckpointIntervalSeconds() { return this.walCheckpointIntervalSeconds; } public EncryptionKeyFormat getEncryptionKeyFormat() { return this.encryptionKeyFormat; } public boolean isDeleteDbFilesOnFailure() { return this.deleteDbFilesOnFailure; } public Optional getEncryptionKey(final CryptoService cryptoService) throws KuraException { if (this.encryptionKey.isPresent()) { String decrypted = new String(cryptoService.decryptAes(this.encryptionKey.get().toCharArray())); final EncryptionKeyFormat format = getEncryptionKeyFormat(); decrypted = format == EncryptionKeyFormat.ASCII ? expectAscii(decrypted) : expectHexString(decrypted); return Optional.of(new EncryptionKeySpec(decrypted, format)); } else { return Optional.empty(); } } public boolean isPeriodicWalCheckpointEnabled() { return this.mode != Mode.IN_MEMORY && this.journalMode == JournalMode.WAL && this.walCheckpointEnabled; } public boolean isPeriodicDefragEnabled() { return this.mode != Mode.IN_MEMORY && this.defragEnabled; } private String expectAscii(final String value) throws KuraException { if (StandardCharsets.US_ASCII.newEncoder().canEncode(value)) { return value; } else { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, "", "Encryption key contains non ASCII characters"); } } private String expectHexString(final String string) throws KuraException { if (string.length() % 2 != 0) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, "", "Hex encryption key length must be a multiple of 2"); } if (!HEX_PATTERN.matcher(string).matches()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ATTRIBUTE_INVALID, ENCRYPTION_KEY, "", "Hex encryption must contain only digits and or letters from \"a\" to \"f\""); } return string.toUpperCase(); } private static Mode extractMode(final Map properties) { try { return Mode.valueOf(MODE_PROPERTY.get(properties)); } catch (final Exception e) { logger.warn("failed to parse db mode, falling back to IN_MEMORY", e); return Mode.IN_MEMORY; } } private static JournalMode extractJournalMode(final Map properties) { try { return JournalMode.valueOf(JOURNAL_MODE_PROPERTY.get(properties)); } catch (final Exception e) { logger.warn("failed to parse db journal mode, falling back to ROLLBACK_JOURNAL", e); return JournalMode.ROLLBACK_JOURNAL; } } public String getDbUrl() { if (this.mode == Mode.PERSISTED) { return "jdbc:sqlite:file:" + this.path; } else { return "jdbc:sqlite:file:" + this.kuraServicePid + "?mode=memory&cache=shared"; } } private static EncryptionKeyFormat extractEncryptionKeyFormat(final Map properties) { try { return EncryptionKeyFormat.valueOf(ENCRYPTION_KEY_FORMAT_PROPERTY.get(properties)); } catch (final Exception e) { return EncryptionKeyFormat.ASCII; } } private static final String sanitizePath(final String path) { final int index = path.indexOf('?'); if (index != -1) { return path.substring(0, index); } else { return path; } } public boolean isDefragEnabled() { return this.defragEnabled; } public boolean isWalCheckpointEnabled() { return this.walCheckpointEnabled; } @Override public int hashCode() { return Objects.hash(this.defragEnabled, this.defragIntervalSeconds, this.deleteDbFilesOnFailure, this.encryptionKey, this.encryptionKeyFormat, this.isDebugShellAccessEnabled, this.journalMode, this.kuraServicePid, this.maxConnectionPoolSize, this.mode, this.path, this.walCheckpointEnabled, this.walCheckpointIntervalSeconds); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if ((obj == null) || (getClass() != obj.getClass())) { return false; } SqliteDbServiceOptions other = (SqliteDbServiceOptions) obj; return this.defragEnabled == other.defragEnabled && this.defragIntervalSeconds == other.defragIntervalSeconds && this.deleteDbFilesOnFailure == other.deleteDbFilesOnFailure && Objects.equals(this.encryptionKey, other.encryptionKey) && this.encryptionKeyFormat == other.encryptionKeyFormat && this.isDebugShellAccessEnabled == other.isDebugShellAccessEnabled && this.journalMode == other.journalMode && Objects.equals(this.kuraServicePid, other.kuraServicePid) && this.maxConnectionPoolSize == other.maxConnectionPoolSize && this.mode == other.mode && Objects.equals(this.path, other.path) && this.walCheckpointEnabled == other.walCheckpointEnabled && this.walCheckpointIntervalSeconds == other.walCheckpointIntervalSeconds; } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteDebugShell.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.sql.Connection; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import org.eclipse.kura.configuration.ConfigurationService; import org.eclipse.kura.db.BaseDbService; import org.eclipse.kura.util.configuration.Property; public class SqliteDebugShell { private static final Property KURA_SERVICE_PID = new Property<>(ConfigurationService.KURA_SERVICE_PID, String.class); private final Map dbServices = new HashMap<>(); private final Set allowedPids = new HashSet<>(); public void setDbService(final BaseDbService dbService, final Map properties) { final Optional kuraServiePid = KURA_SERVICE_PID.getOptional(properties); if (kuraServiePid.isPresent()) { dbServices.put(kuraServiePid.get(), dbService); } } public void unsetDbService(final BaseDbService dbService) { this.dbServices.values().removeIf(s -> s == dbService); } synchronized void setPidAllowed(final String pid, final boolean allowed) { if (!allowed) { this.allowedPids.remove(pid); } else { this.allowedPids.add(pid); } } public synchronized void executeQuery(final String dbServicePid, final String sql) throws SQLException { if (!allowedPids.contains(dbServicePid) || !dbServices.containsKey(dbServicePid)) { throw new IllegalArgumentException("Database instance with pid " + dbServicePid + " is not available"); } final BaseDbService dbService = this.dbServices.get(dbServicePid); try (final Connection conn = dbService.getConnection(); final Statement statement = conn.createStatement()) { final boolean hasResultSet = statement.execute(sql); if (!hasResultSet) { System.out.println(statement.getUpdateCount() + " rows changed"); return; } try (final ResultSet result = statement.getResultSet()) { final ResultSetMetaData meta = result.getMetaData(); final StringBuilder builder = new StringBuilder(); for (int i = 1; i <= meta.getColumnCount(); i++) { builder.append("| ").append(meta.getColumnName(i)).append("\t"); } builder.append("|"); System.out.println(builder.toString()); while (result.next()) { builder.setLength(0); for (int i = 1; i <= meta.getColumnCount(); i++) { builder.append("| ").append(result.getObject(i)).append("\t"); } builder.append("|"); System.out.println(builder.toString()); } } } } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteMessageStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.message.store.AbstractJdbcMessageStoreImpl; import org.eclipse.kura.util.message.store.JdbcMessageStoreQueries; @SuppressWarnings("restriction") public class SqliteMessageStoreImpl extends AbstractJdbcMessageStoreImpl { private static final String CREATE_INDEX_IF_NOT_EXISTS = "CREATE INDEX IF NOT EXISTS "; private static final String UPDATE = "UPDATE "; private static final String DELETE_FROM = "DELETE FROM "; private static final String SELECT_MESSAGE_METADATA_FROM = "SELECT id, topic, qos, retain, createdOn, publishedOn, " + "publishedMessageId, confirmedOn, priority, sessionId, droppedOn FROM "; private final String sqlResetId; private final String sqlDeleteMessage; public SqliteMessageStoreImpl(final ConnectionProvider provider, final String table) throws KuraStoreException { super(provider, table); this.sqlResetId = UPDATE + " sqlite_sequence SET seq = 0 WHERE name = " + this.escapedTableName + ";"; this.sqlDeleteMessage = DELETE_FROM + super.escapedTableName + " WHERE id = ?;"; createTable(); createIndexes(); } @Override protected JdbcMessageStoreQueries buildSqlMessageStoreQueries() { return JdbcMessageStoreQueries.builder() .withSqlCreateTable("CREATE TABLE IF NOT EXISTS " + super.escapedTableName + " (id INTEGER PRIMARY KEY AUTOINCREMENT, topic VARCHAR, qos INTEGER, retain BOOLEAN, " + "createdOn DATETIME, publishedOn DATETIME, publishedMessageId INTEGER, confirmedOn DATETIME, " + "payload BLOB, priority INTEGER, sessionId VARCHAR, droppedOn DATETIME);") .withSqlMessageCount("SELECT COUNT(*) FROM " + super.escapedTableName + ";") .withSqlStore("INSERT INTO " + escapedTableName + " (topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, payload, priority, " + "sessionId, droppedOn) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);") .withSqlGetMessage( "SELECT id, topic, qos, retain, createdOn, publishedOn, publishedMessageId, confirmedOn, " + "payload, priority, sessionId, droppedOn FROM " + super.escapedTableName + " WHERE id = ?") .withSqlGetNextMessage("SELECT a.id, a.topic, a.qos, a.retain, a.createdOn, a.publishedOn, " + "a.publishedMessageId, a.confirmedOn, a.payload, a.priority, a.sessionId, a.droppedOn FROM " + escapedTableName + " AS a JOIN (SELECT id, publishedOn FROM " + super.escapedTableName + " ORDER BY publishedOn ASC NULLS FIRST, priority ASC, createdOn ASC LIMIT 1) AS b " + "WHERE a.id = b.id AND b.publishedOn IS NULL;") .withSqlSetPublishedQoS1(UPDATE + super.escapedTableName + " SET publishedOn = ?, publishedMessageId = ?, sessionId = ? WHERE id = ?;") .withSqlSetPublishedQoS0(UPDATE + super.escapedTableName + " SET publishedOn = ? WHERE id = ?;") .withSqlSetConfirmed(UPDATE + escapedTableName + " SET confirmedOn = ? WHERE id = ?;") .withSqlAllUnpublishedMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE publishedOn IS NULL ORDER BY priority ASC, createdOn ASC;") .withSqlAllInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL AND droppedOn IS NULL " + "ORDER BY priority ASC, createdOn ASC") .withSqlAllDroppedInFlightMessages(SELECT_MESSAGE_METADATA_FROM + super.escapedTableName + " WHERE droppedOn IS NOT NULL ORDER BY priority ASC, createdOn ASC;") .withSqlUnpublishAllInFlightMessages(UPDATE + super.escapedTableName + " SET publishedOn = NULL WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;") .withSqlDropAllInFlightMessages(UPDATE + super.escapedTableName + " SET droppedOn = ? WHERE publishedOn IS NOT NULL AND qos > 0 AND confirmedOn IS NULL;") .withSqlDeleteDroppedMessages( DELETE_FROM + super.escapedTableName + " WHERE droppedOn <= ? AND droppedOn IS NOT NULL;") .withSqlDeleteConfirmedMessages( DELETE_FROM + super.escapedTableName + " WHERE confirmedOn <= ? AND confirmedOn IS NOT NULL;") .withSqlDeletePublishedMessages(DELETE_FROM + super.escapedTableName + " WHERE qos = 0 AND publishedOn <= ? AND publishedOn IS NOT NULL;") .withSqlCreateNextMessageIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_nextMsg") + " ON " + this.escapedTableName + " (publishedOn ASC, priority ASC, createdOn ASC, qos);") .withSqlCreatePublishedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_PUBLISHEDON") + " ON " + this.escapedTableName + " (publishedOn DESC);") .withSqlCreateConfirmedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_CONFIRMEDON") + " ON " + this.escapedTableName + " (confirmedOn DESC);") .withSqlCreateDroppedOnIndex( CREATE_INDEX_IF_NOT_EXISTS + super.escapeIdentifier(super.tableName + "_DROPPEDON") + " ON " + this.escapedTableName + " (droppedOn DESC);") .build(); } @Override public synchronized int store(String topic, byte[] payload, int qos, boolean retain, int priority) throws KuraStoreException { validate(topic); final long id = super.storeInternal(topic, payload, qos, retain, priority); if (id > Integer.MAX_VALUE) { super.execute(this.sqlDeleteMessage, id); if (super.getMessageCountInternal() >= Integer.MAX_VALUE) { throw new KuraStoreException("Table size is greater or equal than integer max value"); } super.execute(this.sqlResetId); return (int) super.storeInternal(topic, payload, qos, retain, priority); } return (int) id; } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteProviderActivator.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.io.File; import java.util.Optional; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class SqliteProviderActivator implements BundleActivator { private static final String SQLITE_TMPDIR_PROPERTY_KEY = "org.sqlite.tmpdir"; private boolean locationChanged = false; @Override public void start(final BundleContext context) throws Exception { final Optional sqliteTmpDir = Optional.ofNullable(System.getProperty(SQLITE_TMPDIR_PROPERTY_KEY)); if (!sqliteTmpDir.isPresent() || !new File(sqliteTmpDir.get()).isDirectory()) { final Optional bundleStorageAreaLocation = Optional.ofNullable(context.getDataFile("")); if (bundleStorageAreaLocation.isPresent()) { System.setProperty(SQLITE_TMPDIR_PROPERTY_KEY, bundleStorageAreaLocation.get().getAbsolutePath()); locationChanged = true; } } } @Override public void stop(final BundleContext context) throws Exception { if (locationChanged) { System.clearProperty(SQLITE_TMPDIR_PROPERTY_KEY); } } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteQueryableWireRecordStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Optional; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.wire.store.AbstractJdbcQueryableWireRecordStoreImpl; @SuppressWarnings("restriction") public class SqliteQueryableWireRecordStoreImpl extends AbstractJdbcQueryableWireRecordStoreImpl { protected SqliteQueryableWireRecordStoreImpl(ConnectionProvider provider) { super(provider); } @Override protected Optional extractColumnValue(ResultSet resultSet, ResultSetMetaData metadata, int columnIndex) throws SQLException { Object dbExtractedData = resultSet.getObject(columnIndex); if (dbExtractedData == null) { return Optional.empty(); } final String typeName = metadata.getColumnTypeName(columnIndex); if ("INT".equals(typeName)) { dbExtractedData = resultSet.getInt(columnIndex); } else if ("BIGINT".equals(typeName) || "INTEGER".equals(typeName)) { dbExtractedData = resultSet.getLong(columnIndex); } else if ("BOOLEAN".equals(typeName)) { dbExtractedData = resultSet.getBoolean(columnIndex); } else if ("BLOB".equals(typeName)) { dbExtractedData = resultSet.getBytes(columnIndex); } return Optional.of(dbExtractedData); } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteUtil.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.sql.Connection; import java.sql.Statement; import org.eclipse.kura.internal.db.sqlite.provider.SqliteDbServiceOptions.JournalMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SqliteUtil { private static final String VACUUM_STATEMENT = "VACUUM;"; private static final String WAL_CHECKPOINT_STATEMENT = "PRAGMA wal_checkpoint(TRUNCATE);"; private static final Logger logger = LoggerFactory.getLogger(SqliteUtil.class); private SqliteUtil() { } public static void walCeckpoint(final Connection connection, final SqliteDbServiceOptions options) { logger.info("performing WAL checkpoint on database with url: {}...", options.getDbUrl()); try (final Statement statement = connection.createStatement()) { statement.executeUpdate(WAL_CHECKPOINT_STATEMENT); } catch (final Exception e) { logger.warn("WAL checkpoint failed", e); } logger.info("performing WAL checkpoint on database with url: {}...done", options.getDbUrl()); } public static void vacuum(final Connection connection, final SqliteDbServiceOptions options) { logger.info("defragmenting database with url: {}...", options.getDbUrl()); try (final Statement statement = connection.createStatement()) { statement.executeUpdate(VACUUM_STATEMENT); } catch (final Exception e) { logger.warn("VACUUM command failed", e); } if (options.getJournalMode() == JournalMode.WAL) { walCeckpoint(connection, options); } logger.info("defragmenting database with url: {}...done", options.getDbUrl()); } } ================================================ FILE: kura/org.eclipse.kura.db.sqlite.provider/src/main/java/org/eclipse/kura/internal/db/sqlite/provider/SqliteWireRecordStoreImpl.java ================================================ /******************************************************************************* * Copyright (c) 2023 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.db.sqlite.provider; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Optional; import org.eclipse.kura.KuraStoreException; import org.eclipse.kura.type.BooleanValue; import org.eclipse.kura.type.ByteArrayValue; import org.eclipse.kura.type.DoubleValue; import org.eclipse.kura.type.FloatValue; import org.eclipse.kura.type.IntegerValue; import org.eclipse.kura.type.LongValue; import org.eclipse.kura.type.StringValue; import org.eclipse.kura.type.TypedValue; import org.eclipse.kura.util.jdbc.ConnectionProvider; import org.eclipse.kura.util.wire.store.AbstractJdbcWireRecordStoreImpl; import org.eclipse.kura.util.wire.store.JdbcWireRecordStoreQueries; @SuppressWarnings("restriction") public class SqliteWireRecordStoreImpl extends AbstractJdbcWireRecordStoreImpl { private static final Map>, String> TYPE_MAPPING = buildTypeMapping(); public SqliteWireRecordStoreImpl(final ConnectionProvider provider, final String tableName) throws KuraStoreException { super(provider, tableName); super.createTable(); super.createTimestampIndex(); } @Override protected JdbcWireRecordStoreQueries buildSqlWireRecordStoreQueries() { return JdbcWireRecordStoreQueries.builder() .withSqlAddColumn("ALTER TABLE " + super.escapedTableName + " ADD COLUMN {0} {1};") .withSqlCreateTable("CREATE TABLE IF NOT EXISTS " + super.escapedTableName + " (ID INTEGER PRIMARY KEY AUTOINCREMENT, TIMESTAMP BIGINT);") .withSqlRowCount("SELECT COUNT(*) FROM " + super.escapedTableName + ";") .withSqlDeleteRangeTable("DELETE FROM " + super.escapedTableName + " WHERE ID IN (SELECT ID FROM " + super.escapedTableName + " ORDER BY ID ASC LIMIT {0});") .withSqlDropColumn("ALTER TABLE " + super.escapedTableName + " DROP COLUMN {0};") .withSqlInsertRecord("INSERT INTO " + super.escapedTableName + " ({0}) VALUES ({1});") .withSqlTruncateTable("DELETE FROM " + super.escapedTableName + ";") .withSqlCreateTimestampIndex( "CREATE INDEX IF NOT EXISTS " + super.escapeIdentifier(tableName + "_TIMESTAMP") + " ON " + super.escapedTableName + " (TIMESTAMP DESC);") .build(); } @Override protected Optional getMappedSqlType(final TypedValue value) { return Optional.ofNullable(value).flatMap(v -> Optional.ofNullable(TYPE_MAPPING.get(v.getClass()))); } private static Map>, String> buildTypeMapping() { final Map>, String> result = new HashMap<>(); result.put(StringValue.class, "TEXT"); result.put(IntegerValue.class, "INT"); result.put(LongValue.class, "BIGINT"); result.put(BooleanValue.class, "BOOLEAN"); result.put(DoubleValue.class, "DOUBLE"); result.put(FloatValue.class, "FLOAT"); result.put(ByteArrayValue.class, "BLOB"); return Collections.unmodifiableMap(result); } } ================================================ FILE: kura/org.eclipse.kura.docs/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.docs Bundle-SymbolicName: org.eclipse.kura.docs Bundle-Version: 1.0.0.qualifier Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" ================================================ FILE: kura/org.eclipse.kura.docs/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.docs/build.properties ================================================ # # Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/ output.. = bin/ bin.includes = META-INF/,\ about.html jars.extra.classpath = platform:/plugin/org.eclipse.kura.api . ================================================ FILE: kura/org.eclipse.kura.docs/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.docs 1.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. 1.6.0 org.eclipse.tycho.extras tycho-document-bundle-plugin ${tycho.extras.version} eclipse-javadoc generate-resources javadoc true -windowtitle "Eclipse Kura ${project.parent.version}" -doctitle "Eclipse Kura ${project.parent.version}" ================================================ FILE: kura/org.eclipse.kura.driver.block/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.driver.block Bundle-SymbolicName: org.eclipse.kura.driver.block Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Import-Package: org.eclipse.kura;version="[1.2, 2.0)", org.eclipse.kura.channel;version="[1.0,2.0)", org.eclipse.kura.channel.listener;version="[1.0, 2.0)", org.eclipse.kura.driver;version="[1.0,2.0)", org.eclipse.kura.type;version="[1.0,2.0)", org.slf4j;version="[1.7, 2.0)" Export-Package: org.eclipse.kura.driver.binary;version="1.1.0", org.eclipse.kura.driver.binary.adapter;version="1.0.0", org.eclipse.kura.driver.block;version="1.0.0", org.eclipse.kura.driver.block.task;version="1.0.0" Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" ================================================ FILE: kura/org.eclipse.kura.driver.block/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.driver.block/build.properties ================================================ source.. = src/main/java/ bin.includes = META-INF/,\ .,\ about.html ================================================ FILE: kura/org.eclipse.kura.driver.block/pom.xml ================================================ 4.0.0 org.eclipse.kura.driver.block 2.0.0-SNAPSHOT eclipse-plugin org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.driver.block.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/AbstractBinaryData.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; import static java.util.Objects.requireNonNull; public abstract class AbstractBinaryData implements BinaryData { protected final Endianness endianness; protected final int size; /** * Creates a new {@link BinaryData} instance. * * @param endianness * the endianness of the data * @param size * the size of the data */ public AbstractBinaryData(Endianness endianness, int size) { requireNonNull(endianness, "Endianness cannot be null"); if (size <= 0) { throw new IllegalArgumentException("Size must be positive"); } this.endianness = endianness; this.size = size; } /** * @return the endianness of the data */ public Endianness getEndianness() { return this.endianness; } /** * @return the size of the data */ public int getSize() { return this.size; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryData.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; /** * This class can be used to read/write a block of data in a {@link Buffer} to/from an instance of type T. * * @param * the type to be used for reading or writing. */ public interface BinaryData { /** * @return the endianness of the data */ public Endianness getEndianness(); /** * @return the size of the data */ public int getSize(); /** * Writes the provided value into the provided {@link Buffer} * * @param buf * a {@link Buffer} instance to be written * @param offset * the offset at which the data will be written * @param value * the value to be written */ public abstract void write(Buffer buf, int offset, T value); /** * * @param buf * a {@link Buffer} from which the data needs to be read * @param the * offset from which the data will be read * @return the obtained value */ public abstract T read(Buffer buf, int offset); public abstract Class getValueType(); } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/BinaryDataTypes.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; import java.util.Arrays; import java.util.Collections; import java.util.List; public final class BinaryDataTypes { public static final BinaryData UINT8 = new UInt8(); public static final BinaryData INT8 = new Int8(); public static final BinaryData UINT16_LE = new UInt16(Endianness.LITTLE_ENDIAN); public static final BinaryData UINT16_BE = new UInt16(Endianness.BIG_ENDIAN); public static final BinaryData INT16_LE = new Int16(Endianness.LITTLE_ENDIAN); public static final BinaryData INT16_BE = new Int16(Endianness.BIG_ENDIAN); public static final BinaryData UINT32_LE = new UInt32(Endianness.LITTLE_ENDIAN); public static final BinaryData UINT32_BE = new UInt32(Endianness.BIG_ENDIAN); public static final BinaryData INT32_LE = new Int32(Endianness.LITTLE_ENDIAN); public static final BinaryData INT32_BE = new Int32(Endianness.BIG_ENDIAN); public static final BinaryData INT64_LE = new Int64(Endianness.LITTLE_ENDIAN); public static final BinaryData INT64_BE = new Int64(Endianness.BIG_ENDIAN); public static final BinaryData FLOAT_LE = new Float(Endianness.LITTLE_ENDIAN); public static final BinaryData FLOAT_BE = new Float(Endianness.BIG_ENDIAN); public static final BinaryData DOUBLE_LE = new Double(Endianness.LITTLE_ENDIAN); public static final BinaryData DOUBLE_BE = new Double(Endianness.BIG_ENDIAN); public static final List NAMES = Collections.unmodifiableList( Arrays.asList("UINT8", "INT8", "UINT16_LE", "UINT16_BE", "INT16_LE", "INT16_BE", "UINT32_LE", "UINT32_BE", "INT32_LE", "INT32_BE", "INT64_LE", "INT64_BE", "FLOAT_LE", "FLOAT_BE", "DOUBLE_LE", "DOUBLE_BE")); public static final List> VALUES = Collections .unmodifiableList(Arrays.asList(UINT8, INT8, UINT16_LE, UINT16_BE, INT16_LE, INT16_BE, UINT32_LE, UINT32_BE, INT32_LE, INT32_BE, INT64_LE, INT64_BE, FLOAT_LE, FLOAT_BE, DOUBLE_LE, DOUBLE_BE)); public static BinaryData parse(String s) { for (int i = 0; i < NAMES.size(); i++) { if (NAMES.get(i).equals(s)) { return VALUES.get(i); } } throw new IllegalArgumentException(); } private BinaryDataTypes() { } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Buffer.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; public interface Buffer { public void put(int offset, byte value); public byte get(int offset); public default void write(int offset, int length, byte[] data) { for (int i = 0; i < length; i++) { put(offset + i, data[i]); } } public default void write(int offset, byte[] data) { write(offset, data.length, data); } public default void read(int offset, int length, byte[] data) { for (int i = 0; i < length; i++) { data[i] = get(offset + i); } } public default void read(int offset, byte[] data) { read(offset, data.length, data); } public default byte[] toArray() { byte[] result = new byte[getLength()]; read(0, result); return result; } public int getLength(); } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArray.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ByteArray extends AbstractBinaryData { private static final Logger logger = LoggerFactory.getLogger(ByteArray.class); public ByteArray(int size) { super(Endianness.LITTLE_ENDIAN, size); } @Override public void write(Buffer buf, int offset, byte[] value) { final int transferSize = getTransferSize(buf, offset); buf.write(offset, transferSize, value); } @Override public byte[] read(final Buffer buf, final int offset) { final int transferSize = getTransferSize(buf, offset); byte[] data = new byte[transferSize]; buf.read(offset, data); return data; } private int getTransferSize(final Buffer buf, final int offset) { final int size = getSize(); final int bufferAvailable = buf.getLength() - offset; if (bufferAvailable < size) { logger.debug("received buffer is too small"); } return Math.min(bufferAvailable, size); } @Override public Class getValueType() { return byte[].class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/ByteArrayBuffer.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; public class ByteArrayBuffer implements Buffer { private final byte[] data; public ByteArrayBuffer(byte[] data) { this.data = data; } @Override public void put(int offset, byte value) { this.data[offset] = value; } @Override public byte get(int offset) { return this.data[offset]; } @Override public int getLength() { return this.data.length; } @Override public void write(int offset, int length, byte[] data) { System.arraycopy(data, 0, this.data, offset, length); } @Override public void read(int offset, int length, byte[] data) { System.arraycopy(this.data, offset, data, 0, length); } public byte[] getBackingArray() { return this.data; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Double.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Double extends AbstractBinaryData { public Double(Endianness endianness) { super(endianness, 8); } @Override public void write(Buffer buf, int offset, java.lang.Double d) { long tmp = java.lang.Double.doubleToRawLongBits(d); if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (tmp >> 56 & 0xff)); buf.put(offset + 1, (byte) (tmp >> 48 & 0xff)); buf.put(offset + 2, (byte) (tmp >> 40 & 0xff)); buf.put(offset + 3, (byte) (tmp >> 32 & 0xff)); buf.put(offset + 4, (byte) (tmp >> 24 & 0xff)); buf.put(offset + 5, (byte) (tmp >> 16 & 0xff)); buf.put(offset + 6, (byte) (tmp >> 8 & 0xff)); buf.put(offset + 7, (byte) (tmp & 0xff)); } else { buf.put(offset, (byte) (tmp & 0xff)); buf.put(offset + 1, (byte) (tmp >> 8 & 0xff)); buf.put(offset + 2, (byte) (tmp >> 16 & 0xff)); buf.put(offset + 3, (byte) (tmp >> 24 & 0xff)); buf.put(offset + 4, (byte) (tmp >> 32 & 0xff)); buf.put(offset + 5, (byte) (tmp >> 40 & 0xff)); buf.put(offset + 6, (byte) (tmp >> 48 & 0xff)); buf.put(offset + 7, (byte) (tmp >> 56 & 0xff)); } } @Override public java.lang.Double read(Buffer buf, int offset) { long tmp; if (this.endianness == Endianness.BIG_ENDIAN) { tmp = buf.get(offset + 7) & 0xffL; tmp |= (buf.get(offset + 6) & 0xffL) << 8; tmp |= (buf.get(offset + 5) & 0xffL) << 16; tmp |= (buf.get(offset + 4) & 0xffL) << 24; tmp |= (buf.get(offset + 3) & 0xffL) << 32; tmp |= (buf.get(offset + 2) & 0xffL) << 40; tmp |= (buf.get(offset + 1) & 0xffL) << 48; tmp |= (buf.get(offset) & 0xffL) << 56; } else { tmp = buf.get(offset) & 0xffL; tmp |= (buf.get(offset + 1) & 0xffL) << 8; tmp |= (buf.get(offset + 2) & 0xffL) << 16; tmp |= (buf.get(offset + 3) & 0xffL) << 24; tmp |= (buf.get(offset + 4) & 0xffL) << 32; tmp |= (buf.get(offset + 5) & 0xffL) << 40; tmp |= (buf.get(offset + 6) & 0xffL) << 48; tmp |= (buf.get(offset + 7) & 0xffL) << 56; } return java.lang.Double.longBitsToDouble(tmp); } @Override public Class getValueType() { return java.lang.Double.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Endianness.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; public enum Endianness { BIG_ENDIAN, LITTLE_ENDIAN } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Float.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Float extends AbstractBinaryData { public Float(Endianness endianness) { super(endianness, 4); } @Override public void write(Buffer buf, int offset, java.lang.Float f) { int tmp = java.lang.Float.floatToRawIntBits(f); if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (tmp >> 24 & 0xff)); buf.put(offset + 1, (byte) (tmp >> 16 & 0xff)); buf.put(offset + 2, (byte) (tmp >> 8 & 0xff)); buf.put(offset + 3, (byte) (tmp & 0xff)); } else { buf.put(offset, (byte) (tmp & 0xff)); buf.put(offset + 1, (byte) (tmp >> 8 & 0xff)); buf.put(offset + 2, (byte) (tmp >> 16 & 0xff)); buf.put(offset + 3, (byte) (tmp >> 24 & 0xff)); } } @Override public java.lang.Float read(Buffer buf, int offset) { int tmp; if (this.endianness == Endianness.BIG_ENDIAN) { tmp = buf.get(offset + 3) & 0xff; tmp |= (buf.get(offset + 2) & 0xff) << 8; tmp |= (buf.get(offset + 1) & 0xff) << 16; tmp |= (buf.get(offset) & 0xff) << 24; } else { tmp = buf.get(offset) & 0xff; tmp |= (buf.get(offset + 1) & 0xff) << 8; tmp |= (buf.get(offset + 2) & 0xff) << 16; tmp |= (buf.get(offset + 3) & 0xff) << 24; } return java.lang.Float.intBitsToFloat(tmp); } @Override public Class getValueType() { return java.lang.Float.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int16.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Int16 extends AbstractBinaryData { public Int16(Endianness endianness) { super(endianness, 2); } @Override public void write(Buffer buf, int offset, Integer value) { final short val = (short) (int) value; if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (val >> 8 & 0xff)); buf.put(offset + 1, (byte) (val & 0xff)); } else { buf.put(offset, (byte) (val & 0xff)); buf.put(offset + 1, (byte) (val >> 8 & 0xff)); } } @Override public Integer read(Buffer buf, int offset) { short result; if (this.endianness == Endianness.BIG_ENDIAN) { result = (short) (buf.get(offset + 1) & 0xff); result |= (buf.get(offset) & 0xff) << 8; } else { result = (short) (buf.get(offset) & 0xff); result |= (buf.get(offset + 1) & 0xff) << 8; } return (int) result; } @Override public Class getValueType() { return Integer.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int32.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Int32 extends AbstractBinaryData { public Int32(Endianness endianness) { super(endianness, 4); } @Override public void write(Buffer buf, int offset, Integer value) { if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (value >> 24 & 0xff)); buf.put(offset + 1, (byte) (value >> 16 & 0xff)); buf.put(offset + 2, (byte) (value >> 8 & 0xff)); buf.put(offset + 3, (byte) (value & 0xff)); } else { buf.put(offset, (byte) (value & 0xff)); buf.put(offset + 1, (byte) (value >> 8 & 0xff)); buf.put(offset + 2, (byte) (value >> 16 & 0xff)); buf.put(offset + 3, (byte) (value >> 24 & 0xff)); } } @Override public Integer read(Buffer buf, int offset) { int result; if (this.endianness == Endianness.BIG_ENDIAN) { result = buf.get(offset + 3) & 0xff; result |= (buf.get(offset + 2) & 0xff) << 8; result |= (buf.get(offset + 1) & 0xff) << 16; result |= (buf.get(offset) & 0xff) << 24; } else { result = buf.get(offset) & 0xff; result |= (buf.get(offset + 1) & 0xff) << 8; result |= (buf.get(offset + 2) & 0xff) << 16; result |= (buf.get(offset + 3) & 0xff) << 24; } return result; } @Override public Class getValueType() { return Integer.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int64.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Int64 extends AbstractBinaryData { public Int64(Endianness endianness) { super(endianness, 8); } @Override public void write(Buffer buf, int offset, Long value) { if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (value >> 56 & 0xff)); buf.put(offset + 1, (byte) (value >> 48 & 0xff)); buf.put(offset + 2, (byte) (value >> 40 & 0xff)); buf.put(offset + 3, (byte) (value >> 32 & 0xff)); buf.put(offset + 4, (byte) (value >> 24 & 0xff)); buf.put(offset + 5, (byte) (value >> 16 & 0xff)); buf.put(offset + 6, (byte) (value >> 8 & 0xff)); buf.put(offset + 7, (byte) (value & 0xff)); } else { buf.put(offset, (byte) (value & 0xff)); buf.put(offset + 1, (byte) (value >> 8 & 0xff)); buf.put(offset + 2, (byte) (value >> 16 & 0xff)); buf.put(offset + 3, (byte) (value >> 24 & 0xff)); buf.put(offset + 4, (byte) (value >> 32 & 0xff)); buf.put(offset + 5, (byte) (value >> 40 & 0xff)); buf.put(offset + 6, (byte) (value >> 48 & 0xff)); buf.put(offset + 7, (byte) (value >> 56 & 0xff)); } } @Override public Long read(Buffer buf, int offset) { long result; if (this.endianness == Endianness.BIG_ENDIAN) { result = buf.get(offset + 7) & 0xffL; result |= (buf.get(offset + 6) & 0xffL) << 8; result |= (buf.get(offset + 5) & 0xffL) << 16; result |= (buf.get(offset + 4) & 0xffL) << 24; result |= (buf.get(offset + 3) & 0xffL) << 32; result |= (buf.get(offset + 2) & 0xffL) << 40; result |= (buf.get(offset + 1) & 0xffL) << 48; result |= (buf.get(offset) & 0xffL) << 56; } else { result = buf.get(offset) & 0xffL; result |= (buf.get(offset + 1) & 0xffL) << 8; result |= (buf.get(offset + 2) & 0xffL) << 16; result |= (buf.get(offset + 3) & 0xffL) << 24; result |= (buf.get(offset + 4) & 0xffL) << 32; result |= (buf.get(offset + 5) & 0xffL) << 40; result |= (buf.get(offset + 6) & 0xffL) << 48; result |= (buf.get(offset + 7) & 0xffL) << 56; } return result; } @Override public Class getValueType() { return Long.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/Int8.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class Int8 extends AbstractBinaryData { public Int8() { super(Endianness.BIG_ENDIAN, 1); } @Override public void write(Buffer buf, int offset, Integer value) { buf.put(offset, (byte) (int) value); } @Override public Integer read(Buffer buf, int offset) { return (int) buf.get(offset); } @Override public Class getValueType() { return Integer.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/TypeUtil.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; import java.math.BigInteger; import java.util.Arrays; import java.util.function.Function; import org.eclipse.kura.type.BooleanValue; import org.eclipse.kura.type.ByteArrayValue; import org.eclipse.kura.type.DataType; import org.eclipse.kura.type.DoubleValue; import org.eclipse.kura.type.FloatValue; import org.eclipse.kura.type.IntegerValue; import org.eclipse.kura.type.LongValue; import org.eclipse.kura.type.StringValue; import org.eclipse.kura.type.TypedValue; public final class TypeUtil { private static final String TO_NATIVE_TYPE_MESSAGE = " to native type "; private static final String CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE = "Cannot convert from Kura data type "; private static final String TO_KURA_DATA_TYPE_MESSAGE = " to Kura data type "; private static final String CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE = "Cannot convert from native type "; private TypeUtil() { } public static Function> toTypedValue(final Class sourceType, final DataType targetType) { if (targetType == DataType.STRING) { return toStringTypedValue(sourceType); } else if (targetType == DataType.BOOLEAN) { return toBooleanTypedValue(sourceType, targetType); } else if (Number.class.isAssignableFrom(sourceType)) { return toNumericalTypedValue(sourceType, targetType); } else if (targetType == DataType.BYTE_ARRAY) { return toByteArrayTypedValue(sourceType, targetType); } else if (sourceType == String.class) { return fromStringValue(targetType); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName() + TO_KURA_DATA_TYPE_MESSAGE + targetType.name()); } private static Function> fromStringValue(final DataType targetType) { if (targetType == DataType.INTEGER) { return value -> new IntegerValue(Integer.parseInt((String) value)); } else if (targetType == DataType.LONG) { return value -> new LongValue(Long.parseLong((String) value)); } else if (targetType == DataType.FLOAT) { return value -> new FloatValue(java.lang.Float.parseFloat((String) value)); } else if (targetType == DataType.DOUBLE) { return value -> new DoubleValue(java.lang.Double.parseDouble((String) value)); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + String.class.getSimpleName() + TO_KURA_DATA_TYPE_MESSAGE + targetType.name()); } private static Function> toNumericalTypedValue(final Class sourceType, final DataType targetType) { if (targetType == DataType.INTEGER) { return value -> new IntegerValue(((Number) value).intValue()); } else if (targetType == DataType.LONG) { return value -> new LongValue(((Number) value).longValue()); } else if (targetType == DataType.FLOAT) { return value -> new FloatValue(((Number) value).floatValue()); } else if (targetType == DataType.DOUBLE) { return value -> new DoubleValue(((Number) value).doubleValue()); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName() + TO_KURA_DATA_TYPE_MESSAGE + targetType.name()); } private static Function> toBooleanTypedValue(final Class sourceType, final DataType targetType) { if (sourceType == Boolean.class) { return value -> new BooleanValue((Boolean) value); } else if (sourceType == String.class) { return value -> new BooleanValue(Boolean.parseBoolean((String) value)); } else if (sourceType.isAssignableFrom(Number.class)) { return value -> new BooleanValue(((Number) value).doubleValue() != 0); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName() + TO_KURA_DATA_TYPE_MESSAGE + targetType.name()); } private static Function> toStringTypedValue(final Class sourceType) { if (sourceType == byte[].class) { return value -> new StringValue(Arrays.toString((byte[]) value)); } else { return value -> new StringValue(value.toString()); } } private static Function> toByteArrayTypedValue(final Class sourceType, final DataType targetType) { if (sourceType == byte[].class) { return value -> new ByteArrayValue((byte[]) value); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_NATIVE_TYPE_MESSAGE + sourceType.getSimpleName() + TO_KURA_DATA_TYPE_MESSAGE + targetType.name()); } public static Function, T> fromTypedValue(final Class targetType, final DataType sourceType) { if (targetType == String.class) { return toStringValue(sourceType); } else if (targetType == Boolean.class) { return toBooleanValue(targetType, sourceType); } else if (targetType == byte[].class) { return toByteArrayValue(targetType, sourceType); } else if (sourceType == DataType.STRING) { return fromStringTypedValue(targetType); } else { return fromNumericTypedValue(targetType, sourceType); } } @SuppressWarnings("unchecked") private static Function, T> fromNumericTypedValue(final Class targetType, final DataType sourceType) { if (targetType == Integer.class) { return value -> (T) (Integer) ((Number) value.getValue()).intValue(); } else if (targetType == Long.class) { return value -> (T) (Long) ((Number) value.getValue()).longValue(); } else if (targetType == java.lang.Float.class) { return value -> (T) (java.lang.Float) ((Number) value.getValue()).floatValue(); } else if (targetType == java.lang.Double.class) { return value -> (T) (java.lang.Double) ((Number) value.getValue()).doubleValue(); } else if (targetType == BigInteger.class) { return value -> (T) BigInteger.valueOf(((Number) value.getValue()).longValue()); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name() + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName()); } @SuppressWarnings("unchecked") private static Function, T> fromStringTypedValue(final Class targetType) { if (targetType == Integer.class) { return value -> (T) (Integer) Integer.parseInt((String) value.getValue()); } else if (targetType == Long.class) { return value -> (T) (Long) Long.parseLong((String) value.getValue()); } else if (targetType == java.lang.Float.class) { return value -> (T) (java.lang.Float) java.lang.Float.parseFloat((String) value.getValue()); } else if (targetType == java.lang.Double.class) { return value -> (T) (java.lang.Double) java.lang.Double.parseDouble((String) value.getValue()); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + DataType.STRING.name() + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName()); } @SuppressWarnings("unchecked") private static Function, T> toBooleanValue(final Class targetType, final DataType sourceType) { if (sourceType == DataType.BOOLEAN) { return value -> (T) value.getValue(); } else if (sourceType == DataType.STRING) { return value -> (T) (Boolean) Boolean.parseBoolean((String) value.getValue()); } else if (sourceType != DataType.BYTE_ARRAY) { return value -> (T) (Boolean) (((Number) value.getValue()).doubleValue() != 0); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name() + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName()); } @SuppressWarnings("unchecked") private static Function, T> toStringValue(final DataType sourceType) { if (sourceType == DataType.BYTE_ARRAY) { return value -> (T) Arrays.toString((byte[]) value.getValue()); } else { return value -> (T) value.toString(); } } @SuppressWarnings("unchecked") private static Function, T> toByteArrayValue(final Class targetType, final DataType sourceType) { if (sourceType == DataType.BYTE_ARRAY) { return value -> (T) (byte[]) value.getValue(); } throw new IllegalArgumentException(CANNOT_CONVERT_FROM_KURA_DATA_TYPE_MESSAGE + sourceType.name() + TO_NATIVE_TYPE_MESSAGE + targetType.getSimpleName()); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt16.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class UInt16 extends AbstractBinaryData { public UInt16(Endianness endianness) { super(endianness, 2); } @Override public void write(Buffer buf, int offset, Integer value) { if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (value >> 8 & 0xff)); buf.put(offset + 1, (byte) (value & 0xff)); } else { buf.put(offset, (byte) (value & 0xff)); buf.put(offset + 1, (byte) (value >> 8 & 0xff)); } } @Override public Integer read(Buffer buf, int offset) { int result; if (this.endianness == Endianness.BIG_ENDIAN) { result = buf.get(offset + 1) & 0xff; result |= (buf.get(offset) & 0xff) << 8; } else { result = buf.get(offset) & 0xff; result |= (buf.get(offset + 1) & 0xff) << 8; } return result; } @Override public Class getValueType() { return Integer.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt32.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class UInt32 extends AbstractBinaryData { public UInt32(Endianness endianness) { super(endianness, 4); } @Override public void write(Buffer buf, int offset, Long value) { if (this.endianness == Endianness.BIG_ENDIAN) { buf.put(offset, (byte) (value >> 24 & 0xff)); buf.put(offset + 1, (byte) (value >> 16 & 0xff)); buf.put(offset + 2, (byte) (value >> 8 & 0xff)); buf.put(offset + 3, (byte) (value & 0xff)); } else { buf.put(offset, (byte) (value & 0xff)); buf.put(offset + 1, (byte) (value >> 8 & 0xff)); buf.put(offset + 2, (byte) (value >> 16 & 0xff)); buf.put(offset + 3, (byte) (value >> 24 & 0xff)); } } @Override public Long read(Buffer buf, int offset) { long result; if (this.endianness == Endianness.BIG_ENDIAN) { result = (long) buf.get(offset + 3) & 0xff; result |= (long) (buf.get(offset + 2) & 0xff) << 8; result |= (long) (buf.get(offset + 1) & 0xff) << 16; result |= (long) (buf.get(offset) & 0xff) << 24; } else { result = buf.get(offset) & 0xff; result |= (long) (buf.get(offset + 1) & 0xff) << 8; result |= (long) (buf.get(offset + 2) & 0xff) << 16; result |= (long) (buf.get(offset + 3) & 0xff) << 24; } return result; } @Override public Class getValueType() { return Long.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UInt8.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; class UInt8 extends AbstractBinaryData { public UInt8() { super(Endianness.BIG_ENDIAN, 1); } @Override public void write(Buffer buf, int offset, Integer value) { buf.put(offset, (byte) (value & 0xff)); } @Override public Integer read(Buffer buf, int offset) { return (int) (buf.get(offset) & 0xff); } @Override public Class getValueType() { return Integer.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/UnsignedIntegerLE.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary; import java.math.BigInteger; public class UnsignedIntegerLE extends AbstractBinaryData { private final int startBitOffset; private final int sizeBits; public UnsignedIntegerLE(final int sizeBits, final int startBitOffset) { super(Endianness.LITTLE_ENDIAN, getSizeBytes(sizeBits)); this.startBitOffset = startBitOffset; this.sizeBits = sizeBits; } @Override public void write(Buffer buf, int offset, BigInteger value) { throw new UnsupportedOperationException(); } @Override public BigInteger read(final Buffer buf, final int offset) { final int sizeBytes = getSize(); final byte[] raw = new byte[sizeBytes]; int srcBit = offset * 8 + startBitOffset; final int srcEnd = srcBit + sizeBits; int dstBit = 0; while (srcBit < srcEnd) { final int srcByte = srcBit / 8; final int dstByte = dstBit / 8; if ((buf.get(srcByte) & 0xff & (1 << (srcBit % 8))) != 0) { raw[dstByte] |= (1 << (dstBit % 8)); } srcBit++; dstBit++; } for (int i = 0; i < sizeBytes / 2; i++) { final byte tmp = raw[i]; raw[i] = raw[sizeBytes - i - 1]; raw[sizeBytes - i - 1] = tmp; } return new BigInteger(1, raw); } @Override public Class getValueType() { return BigInteger.class; } private static int getSizeBytes(final int sizeBits) { if (sizeBits <= 0) { throw new IllegalArgumentException("bit size must be positive"); } return (int) Math.ceil((double) sizeBits / 8); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/GainOffset.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary.adapter; import java.math.BigInteger; import java.util.function.Function; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.driver.binary.Endianness; public class GainOffset implements BinaryData { private final double gain; private final double off; private final Adapter adapter; public GainOffset(final BinaryData wrapped, final double gain, final double offset) { this.gain = gain; this.off = offset; this.adapter = new Adapter<>(wrapped); } @Override public void write(final Buffer buf, final int offset, final Double value) { final double d = value * gain + off; adapter.write(buf, offset, d); } @Override public Double read(Buffer buf, int offset) { return adapter.read(buf, offset) * gain + off; } @Override public Class getValueType() { return Double.class; } @Override public Endianness getEndianness() { return adapter.getWrapped().getEndianness(); } @Override public int getSize() { return adapter.getWrapped().getSize(); } private static class Adapter { private final BinaryData wrapped; private final Function fromDouble; public Adapter(final BinaryData wrapped) { this.wrapped = wrapped; this.fromDouble = fromDouble(wrapped.getValueType()); } @SuppressWarnings("unchecked") private static Function fromDouble(final Class targetType) { if (targetType == Byte.class) { return value -> (T) (Byte) value.byteValue(); } else if (targetType == Short.class) { return value -> (T) (Short) value.shortValue(); } else if (targetType == Integer.class) { return value -> (T) (Integer) value.intValue(); } else if (targetType == Long.class) { return value -> (T) (Long) value.longValue(); } else if (targetType == java.lang.Float.class) { return value -> (T) (Float) value.floatValue(); } else if (targetType == java.lang.Double.class) { return value -> (T) (Double) value.doubleValue(); } else if (targetType == BigInteger.class) { return value -> (T) BigInteger.valueOf(value.longValue()); } throw new IllegalArgumentException("cannot convert from double to " + targetType.getSimpleName()); } public void write(final Buffer buf, final int offset, final Double value) { wrapped.write(buf, offset, fromDouble.apply(value)); } public Double read(final Buffer buf, final int offset) { return wrapped.read(buf, offset).doubleValue(); } public BinaryData getWrapped() { return wrapped; } } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/StringData.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary.adapter; import java.nio.charset.Charset; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.driver.binary.Endianness; public class StringData implements BinaryData { private final BinaryData wrapped; private final Charset charset; public StringData(final BinaryData wrapped, final Charset charset) { this.wrapped = wrapped; this.charset = charset; } @Override public Endianness getEndianness() { return wrapped.getEndianness(); } @Override public int getSize() { return wrapped.getSize(); } @Override public void write(Buffer buf, int offset, String value) { final byte[] raw = value.getBytes(charset); wrapped.write(buf, offset, raw); } @Override public String read(Buffer buf, int offset) { final byte[] raw = wrapped.read(buf, offset); return new String(raw, charset); } @Override public Class getValueType() { return String.class; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/binary/adapter/ToBoolean.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.binary.adapter; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.driver.binary.Endianness; public class ToBoolean implements BinaryData { final BinaryData wrapped; public ToBoolean(final BinaryData wrapped) { this.wrapped = wrapped; } @Override public void write(final Buffer buf, final int offset, final Boolean value) { throw new UnsupportedOperationException(); } @Override public Boolean read(final Buffer buf, int offset) { return ((Number) wrapped.read(buf, offset)).doubleValue() != 0; } @Override public Class getValueType() { return Boolean.class; } @Override public Endianness getEndianness() { return wrapped.getEndianness(); } @Override public int getSize() { return wrapped.getSize(); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/Block.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block; /** * A {@link Block} instance represents an interval on an abstract addressing space (e.g. a set of consecutive Modbus * registers or coils). */ public class Block { private int start; private int end; /** * Creates a new {@link Block} instance. If the provided start address is lesser than the provided end address, the * two addresses will be swapped. * * @param start * the start address * @param end * the end address */ public Block(int start, int end) { this.start = Math.min(start, end); this.end = Math.max(start, end); } /** * Sets the start address * * @param start * the start address * @throws IllegalArgumentException * If the provided address is greater than the current end address */ public void setStart(int start) { if (start > getEnd()) { throw new IllegalArgumentException("Start address must be less or equal than end address"); } this.start = start; } /** * Sets the end address * * @param end * the end address * @throws IllegalArgumentException * If the provided address is greater than the current start address */ public void setEnd(int end) { if (end < getStart()) { throw new IllegalArgumentException("Start address must be less or equal than end address"); } this.end = end; } /** * Returns the start address * * @return the start address */ public int getStart() { return this.start; } /** * Returns the end address * * @return the end address */ public int getEnd() { return this.end; } /** * Checks whether the provided address is contained by the interval represented by this {@link Block}. * This method returns true if {@code getStart() <= address && getEnd() > address} * * @param address * the address to be checked * @return {@code true} if the provided address is contained in this {@link Block}, {@code false} otherwise */ public boolean contains(int address) { return this.start <= address && this.end > address; } /** * Checks whether the provided {@link Block} is contained by the interval represented by this {@link Block}. * This method returns true if {@code this.getStart() <= other.getStart() && this.getEnd() >= other.getEnd()} * * @param address * the {@link Block} to be checked * @return {@code true} if the provided address is contained in this {@link Block}, {@code false} otherwise */ public boolean contains(Block other) { return this.start <= other.start && this.end >= other.end; } @Override public String toString() { return "[" + this.start + ", " + this.end + "]"; } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/BlockAggregator.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block; import static java.util.Objects.requireNonNull; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Stream; import java.util.stream.StreamSupport; /** * This class can be used to perform an aggregation process over a given list of blocks. * * The block set resulting from the aggregation always has the following properties: *
    *
  • It does not contain prohibited blocks (see {@link ProhibitedBlock})
  • *
  • It does not contain overlapping blocks
  • *
  • For each pair of blocks (b1, b2) belonging to the set, {@code b1.getStart() != b2.getEnd()}
  • *
* * This class accepts a parameter, {@code minimumGapSize >= 0}: *
    *
  • If {@code minimumGapSize == 0 || minimumGapSize == 1} the resulting block set will represent the union of the * intervals represented by * the input block set.
  • *
  • If {@code minimumGapSize > 1} two non overlapping input blocks i1 and i2 such that * {@code i1.getEnd() < i2.getStart()} might be aggregated into a new block b2 such that * {@code b2.getStart() = i1.getStart()} and {@code b2.getEnd() = i2.getEnd()} if {@code i2.getStart() - i1.getEnd()} * is lesser than {@code minimumGapSize}
  • *
* *

* The input block list must not contain conflicting blocks (two overlapping blocks such as one is prohibited and the * other is not). If this requirement is not satisfied the aggregation process will fail (see * {@link BlockAggregator#stream()}). *

* *

* The input block list can represent for example a list of addresses that need to be read/written from/to a remote * device using a specific protocol. * If the protocol allows to performs bulk read/writes (for example Modbus allows to read multiple consecutive * coils/register using a single request) this class can be used to aggregate a set of multiple "small" requests * spanning consecutive addresses into fewer and "larger" requests, reducing I/O time. *

* *

* The {@code minimumGapSize} parameter can be used to aggregate requests involving non consecutive intervals if they * are "close enough" according to the above criterion. In this case non explicitly requested data will be * transfered. *

* * @param * The type of the blocks obtained as result of the aggregation process. */ public class BlockAggregator { protected List blocks; private final BlockFactory factory; private int minimumGapSize; /** * Creates a new {@link BlockAggregator} instance that operates on the given list of blocks. * The provided list must be mutable as it will be sorted every time the {@link BlockAggregator#stream()} method is * called. * * @param inputBlocks * a mutable list of input blocks. * @param factory * a {@link BlockFactory} instance that will be used to create the output blocks during the aggregation * process. */ public BlockAggregator(List inputBlocks, BlockFactory factory) { requireNonNull(inputBlocks, "Input block list cannot be null"); requireNonNull(factory, "Block factory cannot be null"); this.blocks = inputBlocks; this.factory = factory; } /** *

* Sorts the input block list and the returns a {@link Stream} that yields the output blocks obtained from the * aggregation process. *

*

* The aggregation of the input blocks is performed lazily: the output blocks are produced on the fly when a * terminal operation is applied to the resulting {@link Stream}. * A terminal operation can be the iteration over an {@link Iterator} obtained from the {@link Stream}, or the * invocation of the {@link Stream#collect(java.util.stream.Collector)} method. *

*

* Note: If the input block list contains conflicting blocks an {@link IllegalArgumentException} will be * thrown when the stream is consumed as soon as the conflict is detected. *

* * @return the resulting {@link Stream} */ @SuppressWarnings("unchecked") public Stream stream() { this.blocks.sort((Block o1, Block o2) -> o1.getStart() - o2.getStart()); return (Stream) StreamSupport .stream(Spliterators.spliteratorUnknownSize(new AggregatingIterator(this.blocks.listIterator()), Spliterator.ORDERED), false) .filter(block -> !(block instanceof ProhibitedBlock)); } /** * Specifies the {@code minimumGapSize} parameter. The default for this parameter is 0. * * @param minimumGapSize * @throws IllegalArgumentException * If the provided argument is negative */ public void setMinimumGapSize(int minimumGapSize) { if (minimumGapSize < 0) { throw new IllegalArgumentException("Minimum gap size paramenter must be non negative"); } this.minimumGapSize = minimumGapSize; } /** * Inserts a new {@link Block} into the input blocks list. * * @param block * the block to be inserted. */ public void addBlock(Block block) { requireNonNull(block, "The provided block cannot be null"); this.blocks.add(block); } private class AggregatingIterator implements Iterator { private final ListIterator source; private Block last; public AggregatingIterator(ListIterator source) { this.source = source; } private void extend(Block block, int end) { block.setEnd(Math.max(block.getEnd(), end)); } private void getNext() { if (!this.source.hasNext()) { return; } this.last = this.source.next(); if (!(this.last instanceof ProhibitedBlock)) { this.last = BlockAggregator.this.factory.build(this.last.getStart(), this.last.getEnd()); } while (this.source.hasNext()) { final Block next = this.source.next(); final boolean isTypeDifferent = this.last instanceof ProhibitedBlock ^ next instanceof ProhibitedBlock; if (this.last.getEnd() < next.getStart()) { if (BlockAggregator.this.minimumGapSize > 0 && next.getStart() - this.last.getEnd() < BlockAggregator.this.minimumGapSize && !isTypeDifferent) { extend(this.last, next.getEnd()); continue; } else { this.source.previous(); break; } } if (this.last.getEnd() > next.getStart() && isTypeDifferent) { throw new IllegalArgumentException("Conflicting blocks: " + this.last + " " + next); } if (isTypeDifferent) { this.source.previous(); break; } extend(this.last, next.getEnd()); } } @Override public boolean hasNext() { if (this.last == null) { getNext(); } return this.last != null; } @Override public Block next() { if (this.last == null) { getNext(); } if (this.last == null) { throw new NoSuchElementException(); } Block result = this.last; this.last = null; return result; } } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/BlockFactory.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block; /** * This class is responsible of creating new blocks of type {@code T}. * * @param * The type of the returned block */ public interface BlockFactory { /** * Creates a new block of type T, with the given start and end addresses. * * @param start * the start address of the new block * @param end * the end address of the new block * @return The new block */ public T build(int start, int end); } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/ProhibitedBlock.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block; /** * This class represents a prohibited interval over an abstract addressing space, that is an interval of addresses on * which it is not permitted to perform a specific operation (e.g. a non readable or non writable area). * * @see Block */ public class ProhibitedBlock extends Block { public ProhibitedBlock(int start, int end) { super(start, end); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/AbstractBlockDriver.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import static java.util.Objects.requireNonNull; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.KuraRuntimeException; import org.eclipse.kura.channel.ChannelFlag; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.channel.ChannelStatus; import org.eclipse.kura.channel.listener.ChannelListener; import org.eclipse.kura.driver.Driver; import org.eclipse.kura.driver.PreparedRead; import org.eclipse.kura.driver.block.Block; import org.eclipse.kura.driver.block.BlockFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** *

* Provides an helper class that can be extended for implementing a {@link Driver} that supports the aggregation of * requests using a {@link BlockTaskAggregator}. *

*

* This class introduces the concept of domain. In general tasks that operate on different domains cannot be aggregated * together. Examples of such domains can be a (unit id, function code) pair in the Modbus protocol or a data block * (DB) in the case of the S7Comm protocol. *

*

* Implementors of this class must provide an implementation for the * {@link #getTaskFactoryForDomain(Object, Mode)} and {@link #toTasks(List, Mode)} * methods, see the description of the two methods for more details: *

*
    *
  • {@link #getTaskFactoryForDomain(Object, Mode)} must provide a {@link BlockFactory} that can be used for creating * {@link ToplevelBlockTask} instances responsible of implementing the data transfer operations for the specified * domain
  • *
  • {@link #toTasks(List, Mode)} must convert the configuration contained in the provided list of * {@link ChannelRecord} instances into a {@link Stream} of (domain, {@link BlockTask}) pairs.
  • *
*

* This class provides a default implementation for the {@link #read(List)}, {@link #write(List)} and * {@link #prepareRead(List)} methods of the {@link Driver} interface. *

* * @param * the type of the domain, can be any type suitable for being used as an {@link java.util.HashMap} key */ public abstract class AbstractBlockDriver implements Driver { private static final Logger logger = LoggerFactory.getLogger(AbstractBlockDriver.class); /** * This method must provide a {@link BlockFactory} that can be used for creating {@link ToplevelBlockTask} instances * responsible of implementing the I/O operations for the specified domain. * * @param domain * the domain * @param mode * the {@link Mode} for the returned {@link ToplevelBlockTask} * @return the created {@link ToplevelBlockTask} */ protected abstract BlockFactory getTaskFactoryForDomain(T domain, Mode mode); /** *

* This method must return a {@link Stream} that yields (domain, {@link BlockTask}) pairs obtained by converting the * {@link ChannelRecord} instances contained in the provided list. *

*

* The {@link BlockTask} instances obtained from the stream will be aggregated and assigned to a * {@link ToplevelBlockTask} parent. Tasks generated by the {@link Stream} returned by this method should not * generally perform I/O operation but use the {@link Buffer} of their parent to implement their operations instead. *

*

* If the specified mode is {@link Mode#READ}, only tasks having {@link Mode#READ} must be produces, if the * specified mode is {@link Mode#WRITE}, the returned stream is allowed to produce tasks that are either in * {@link Mode#WRITE} or {@link Mode#UPDATE} modes. *

* * * @param records * the list of {@link ChannelRecord} instances to be converted into {@link BlockTask} instances * @param mode * the mode, can be either {@link Mode#READ} or {@link Mode#WRITE} * @return a {@link Stream} yielding the converted tasks */ protected abstract Stream> toTasks(List records, Mode mode); /** * Returns the minimum gap size parameter that will be used to aggregate tasks in {@link Mode#READ} for the * specified domain. The default is 0. Tasks in {@link Mode#WRITE} mode will always be aggregated using 0 as the * value of the {@code minimumGapSize} parameter. * * @param domain * the domain * @return the minimum gap size for the provided domain */ protected int getReadMinimumGapSizeForDomain(T domain) { return 0; } /** * This method is called immediately before an aggregation is performed for the specific domain and mode. This * method can be overridden by implementors in order to customize the {@link BlockTaskAggregator} provided as * argument, for example by adding prohibited blocks. The default implementation is no-op. * * @param domain * the domain * @param mode * the {@link Mode} of the tasks to be aggregated, can be either {@link Mode#READ} or {@link Mode#WRITE} * @param aggregator * the {@link BlockTaskAggregator} that will perform the aggregation */ protected void beforeAggregation(T domain, Mode mode, BlockTaskAggregator aggregator) { } /** * Perform the following operations: *
    *
  1. The provided list of {@link ChannelRecods} instances are converted into {@link BlockTask} instances using the * {@link #toTasks(List, Mode)} method.
  2. *
  3. The resulting {@link BlockTask} instances are grouped by domain.
  4. *
  5. An aggregation process is performed for each domain. If the {@link Mode#WRITE} is provided as parameter, and * tasks in {@link Mode#UPDATE} mode are found in a domain, the aggregation will be performed using a * {@link UpdateBlockTaskAggregator}. Otherwise a {@link BlockTaskAggregator} will be used.
    * The {@link BlockFactory} instances used for the aggregation will be obtained using the * {@link #getTaskFactoryForDomain(Object, Mode)} method.
  6. *
  7. The {@link ToplevelBlockTask} instances for all domains will be returned in the result list.
  8. *
* * @param records * the {@link ChannelRecord} instances to be converted to {@link BlockTask} instances. * @param mode * the mode * @return the list of {@link BlockTask} instances resulting from the aggregation. * @throws KuraException * if any exception is thrown during the process */ protected List optimize(List records, Mode mode) throws KuraException { try { final ArrayList resultTasks = new ArrayList<>(); final HashSet domainsWithUpdateTasks = new HashSet<>(); final Function, T> classifier; if (mode == Mode.READ) { classifier = pair -> pair.first; } else { classifier = pair -> { if (pair.second.getMode() == Mode.UPDATE) { domainsWithUpdateTasks.add(pair.first); } return pair.first; }; } final Map> groupedTasks = toTasks(records, mode).collect(Collectors.groupingBy( classifier, Collectors.mapping(pair -> pair.second, Collectors.toCollection(ArrayList::new)))); groupedTasks.entrySet().forEach(entry -> { final T domain = entry.getKey(); final BlockTaskAggregator aggregator; if (domainsWithUpdateTasks.contains(domain)) { aggregator = new UpdateBlockTaskAggregator(entry.getValue(), getTaskFactoryForDomain(domain, Mode.READ), getTaskFactoryForDomain(domain, Mode.WRITE)); aggregator.setMinimumGapSize(getReadMinimumGapSizeForDomain(domain)); } else { aggregator = new BlockTaskAggregator(entry.getValue(), getTaskFactoryForDomain(domain, mode)); if (mode == Mode.READ) { aggregator.setMinimumGapSize(getReadMinimumGapSizeForDomain(domain)); } } beforeAggregation(domain, mode, aggregator); aggregator.stream().forEach(resultTasks::add); }); return resultTasks; } catch (Exception e) { throw new KuraException(KuraErrorCode.INVALID_PARAMETER, e); } } /** * Executes the provided {@link BlockTask}. Implementors can override this method, for example for catching any * exception thrown by the task and implement error handling. * * @param task * the {@link BlockTask} to be run */ protected void runTask(BlockTask task) { try { task.run(); } catch (Exception e) { logger.warn("Task execution failed", e); } } @Override public void registerChannelListener(final Map channelConfig, final ChannelListener listener) throws ConnectionException { throw new KuraRuntimeException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "register listener"); } @Override public void unregisterChannelListener(final ChannelListener listener) throws ConnectionException { throw new KuraRuntimeException(KuraErrorCode.OPERATION_NOT_SUPPORTED, "unregister listener"); } @Override public synchronized void read(final List records) throws ConnectionException { connect(); try { optimize(records, Mode.READ).forEach(this::runTask); } catch (Exception e) { logger.warn("Unexpected exception during read", e); for (ChannelRecord record : records) { record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e)); record.setTimestamp(System.currentTimeMillis()); } } } @Override public synchronized void write(final List records) throws ConnectionException { connect(); try { optimize(records, Mode.WRITE).forEach(this::runTask); } catch (Exception e) { logger.warn("Unexpected exception during write", e); for (ChannelRecord record : records) { record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e)); record.setTimestamp(System.currentTimeMillis()); } } } protected PreparedRead createPreparedRead(List records, List tasks) { return new BlockPreparedRead(records, tasks); } @Override public synchronized PreparedRead prepareRead(List records) { try { return createPreparedRead(records, optimize(records, Mode.READ)); } catch (KuraException e) { for (ChannelRecord record : records) { record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e)); record.setTimestamp(System.currentTimeMillis()); } return createPreparedRead(records, Collections.emptyList()); } } public class BlockPreparedRead implements PreparedRead { private final List records; private final List tasks; public BlockPreparedRead(List records, List tasks) { this.records = records; this.tasks = tasks; } @Override public void close() throws Exception { } @Override public List execute() throws ConnectionException, KuraException { synchronized (AbstractBlockDriver.this) { connect(); for (BlockTask task : this.tasks) { runTask(task); } return this.records; } } @Override public List getChannelRecords() { return this.records; } } public static final class Pair { private final U first; private final V second; public Pair(U first, V second) { requireNonNull(first); requireNonNull(second); this.first = first; this.second = second; } public U getFirst() { return first; } public V getSecond() { return second; } } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BinaryDataTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import java.io.IOException; import java.util.function.Function; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.binary.BinaryData; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.driver.binary.TypeUtil; import org.eclipse.kura.type.DataType; import org.eclipse.kura.type.TypedValue; import org.eclipse.kura.type.TypedValues; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BinaryDataTask extends ChannelBlockTask { private static final Logger logger = LoggerFactory.getLogger(BinaryDataTask.class); private BinaryData dataType; private Function> toTypedValue; private Function, T> fromTypedValue; @SuppressWarnings("unchecked") public BinaryDataTask(ChannelRecord record, int offset, BinaryData dataType, Mode mode) { this(record, offset, dataType, TypedValues::newTypedValue, typedValue -> (T) typedValue.getValue(), mode); } public BinaryDataTask(ChannelRecord record, int offset, BinaryData binaryDataType, DataType dataType, Mode mode) { this(record, offset, binaryDataType, TypeUtil.toTypedValue(binaryDataType.getValueType(), dataType), TypeUtil.fromTypedValue(binaryDataType.getValueType(), dataType), mode); } public BinaryDataTask(ChannelRecord record, int offset, BinaryData dataType, Function> toTypedValue, Function, T> fromTypedValue, Mode mode) { super(record, offset, offset + dataType.getSize(), mode); this.dataType = dataType; this.toTypedValue = toTypedValue; this.fromTypedValue = fromTypedValue; } @Override public void run() throws IOException { final ToplevelBlockTask parent = getParent(); Buffer buffer = parent.getBuffer(); if (getMode() == Mode.READ) { logger.debug("Read {}: offset: {}", this.dataType.getClass().getSimpleName(), getStart()); final T result = this.dataType.read(buffer, getStart() - parent.getStart()); this.record.setValue(this.toTypedValue.apply(result)); onSuccess(); } else { logger.debug("Write {}: offset: {}", this.dataType.getClass().getSimpleName(), getStart()); T value = this.fromTypedValue.apply(this.record.getValue()); this.dataType.write(buffer, getStart() - parent.getStart(), value); } } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BitTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.type.BooleanValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BitTask extends UpdateBlockTask { private static final Logger logger = LoggerFactory.getLogger(BitTask.class); private int bit; public BitTask(ChannelRecord record, int start, int bit, Mode mode) { super(record, start, start + 1, mode); this.bit = bit; } public void setBit(int bit) { this.bit = bit; } @Override protected void runRead() { final ToplevelBlockTask parent = getParent(); Buffer buffer = parent.getBuffer(); byte b = buffer.get(getStart() - parent.getStart()); final boolean result = (b >> this.bit & 0x01) == 1; logger.debug("Reading Bit: offset {} bit index {} result {}", getStart(), this.bit, result); this.record.setValue(new BooleanValue(result)); onSuccess(); } @Override protected void runWrite() { logger.warn("Write mode not supported"); onFailure(new UnsupportedOperationException( "BitTask does not support WRITE mode, only READ and UPDATE modes are supported")); } @Override protected void runUpdate(ToplevelBlockTask write, ToplevelBlockTask read) { Buffer outBuffer = write.getBuffer(); Buffer inBuffer = read.getBuffer(); final int previousValueOffset = getStart() - read.getStart(); final boolean value = (Boolean) this.record.getValue().getValue(); byte byteValue = inBuffer.get(previousValueOffset); if (value) { byteValue |= 1 << this.bit; } else { byteValue &= ~(1 << this.bit); } inBuffer.put(previousValueOffset, byteValue); logger.debug("Write Bit: offset: {} value: {}", getStart(), value); outBuffer.put(getStart() - write.getStart(), byteValue); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import static java.util.Objects.requireNonNull; import java.io.IOException; import org.eclipse.kura.driver.block.Block; /** * This class represents an generic operation that involves a specific interval of addresses on a given address space. * * @see BlockTaskAggregator * @see ToplevelBlockTask */ public abstract class BlockTask extends Block { private final Mode mode; private ToplevelBlockTask parent; /** * Creates a new {@link BlockTask} * * @param start * the start address of the interval involved by the operation * @param end * the end address of the interval involved by the operation * @param mode * the {@link Mode} of the operation */ public BlockTask(int start, int end, Mode mode) { super(start, end); requireNonNull(mode, "The provided mode cannot be null"); this.mode = mode; } /** * Sets the parent of this task. * * @see BlockTaskAggregator * @param parent * the parent task */ public void setParent(ToplevelBlockTask parent) { this.parent = parent; } /** * Returns the parent of this task. * * @return the parent task, or {@code null} if this task has no parent. */ public ToplevelBlockTask getParent() { return this.parent; } /** * Returns the {@link Mode} of this task. * * @return the {@link Mode} of this task */ public Mode getMode() { return this.mode; } /** * Performs the operation described by this task. * * @throws IOException * If an I/O error occurs during the operation */ public abstract void run() throws IOException; /** * Notifies this task that the operation performed by the parent task is failed. * * @param reason * An {@link Exception} instance describing the reason of the failure */ public abstract void onFailure(Exception exception); /** * Notifies this task that the operation performed by the parent task failed. */ public abstract void onSuccess(); } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/BlockTaskAggregator.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import java.util.List; import java.util.ListIterator; import java.util.stream.Stream; import org.eclipse.kura.driver.block.Block; import org.eclipse.kura.driver.block.BlockAggregator; import org.eclipse.kura.driver.block.BlockFactory; /** *

* Represents a specialized version of {@link BlockAggregator} that operates on {@link BlockTask} instances. * This class performs the aggregation of the input blocks in the same way as {@link BlockAggregator} does, and always * returns {@link ToplevelBlockTask} instances as result of the aggregation. *

* *

* If any {@link BlockTask} is found in the input block list, it will be assigned to the proper parent task in the * result list, basing on the start and end addresses of the two tasks. *

* *

* The result of the aggregation performed by this class is therefore a generally two level tree structure: the first * level of * the tree is composed by {@link ToplevelBlockTask} instances responsible of managing a data buffer, the second level * is composed by {@link BlockTask} instances that perform an operation using the buffer of the parent. See * {@link ToplevelBlockTask} for more information on this structure. *

* * @see ToplevelBlockTask * @see BlockTask */ public class BlockTaskAggregator extends BlockAggregator { /** * Creates a new {@link BlockAggregator} instance that operates on the given list of blocks. * The provided list must be mutable as it will be sorted every time the {@link BlockAggregator#stream()} method is * called. * * @param inputBlocks * a mutable list of input blocks. * @param factory * a {@link BlockFactory} instance that will be used to create the output blocks during the aggregation * process. */ public BlockTaskAggregator(List tasks, BlockFactory factory) { super(tasks, factory); } @SuppressWarnings("checkstyle:innerAssignment") private void assignTasks(ToplevelBlockTask toplevelTask, ListIterator tasks) { Block next = null; while (tasks.hasNext() && (next = tasks.next()).getEnd() <= toplevelTask.getEnd()) { if (next instanceof BlockTask) { toplevelTask.addChild((BlockTask) next); } } if (next != null) { tasks.previous(); } } /** * {@inheritDoc} */ @Override public Stream stream() { final Stream result = super.stream(); final ListIterator blocks = this.blocks.listIterator(); return result.map(toplevelTask -> { assignTasks(toplevelTask, blocks); return toplevelTask; }); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ByteArrayTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.binary.ByteArray; public class ByteArrayTask extends BinaryDataTask { public ByteArrayTask(ChannelRecord record, int start, int end, Mode mode) { super(record, start, new ByteArray(end - start), mode); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import static java.util.Objects.requireNonNull; import org.eclipse.kura.channel.ChannelFlag; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.channel.ChannelStatus; /** * A {@link BlockTask} that performs an operation involving a {@link ChannelRecord}. For example a * {@link ChannelBlockTask} instance in {@link Mode#READ} mode could extract some data from the {@link Buffer} of its * parent and store it in the {@link ChannelRecord}. * */ public abstract class ChannelBlockTask extends BlockTask { protected final ChannelRecord record; /** * Creates a new {@link ChannelBlockTask} instance. * * @param record * the {@link ChannelRecord} instance * @param start * the start address for this task * @param end * the end address for this task * @param mode * the mode of this task */ public ChannelBlockTask(ChannelRecord record, int start, int end, Mode mode) { super(start, end, mode); requireNonNull(record, "The provided channel record cannot be null"); this.record = record; } public ChannelRecord getRecord() { return record; } /** * Sets the {@link ChannelStatus} of the associated {@link ChannelRecord} to report a success state * and updates the timestamp. */ @Override public void onSuccess() { this.record.setChannelStatus(new ChannelStatus(ChannelFlag.SUCCESS)); this.record.setTimestamp(System.currentTimeMillis()); } /** * Sets the {@link ChannelStatus} of the associated {@link ChannelRecord} to report the exception reported as * parameter and updates the timestamp. */ @Override public void onFailure(Exception exception) { this.record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, null, exception)); this.record.setTimestamp(System.currentTimeMillis()); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelBlockTaskWrapper.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; public abstract class ChannelBlockTaskWrapper extends ChannelBlockTask { private final ChannelBlockTask wrapped; public ChannelBlockTaskWrapper(final ChannelBlockTask wrapped) { super(wrapped.getRecord(), wrapped.getStart(), wrapped.getEnd(), wrapped.getMode()); this.wrapped = wrapped; } public ChannelBlockTask getWrappedTask() { return wrapped; } @Override public void setParent(final ToplevelBlockTask parent) { super.setParent(parent); wrapped.setParent(parent); } @Override public int getStart() { return wrapped.getStart(); } @Override public int getEnd() { return wrapped.getEnd(); } @Override public void setEnd(int end) { super.setEnd(end); wrapped.setEnd(end); } @Override public void setStart(int start) { super.setStart(start); wrapped.setStart(start); } @Override public void onSuccess() { wrapped.onSuccess(); } @Override public void onFailure(final Exception exception) { wrapped.onFailure(exception); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ChannelListenerBlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import java.io.IOException; import org.eclipse.kura.channel.listener.ChannelEvent; import org.eclipse.kura.channel.listener.ChannelListener; public class ChannelListenerBlockTask extends ChannelBlockTaskWrapper { private final ChannelListener listener; public ChannelListenerBlockTask(final ChannelBlockTask wrapped, final ChannelListener listener) { super(wrapped); this.listener = listener; } public ChannelListener getListener() { return listener; } @Override public void run() throws IOException { final ChannelBlockTask wrapped = getWrappedTask(); wrapped.run(); listener.onChannelEvent(new ChannelEvent(wrapped.getRecord())); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/Mode.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; /** * Describes an operation performed by a {@link BlockTask}. */ public enum Mode { /** * The operation is a read */ READ, /** * The operation is a write */ WRITE, /** * The operation is a read-update-write. * * @see UpdateBlockTask * @see UpdateBlockTaskAggregator */ UPDATE } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/StringTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import java.nio.charset.StandardCharsets; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.driver.binary.ByteArray; import org.eclipse.kura.driver.binary.adapter.StringData; public class StringTask extends BinaryDataTask { public StringTask(ChannelRecord record, int start, int end, Mode mode) { super(record, start, new StringData(new ByteArray(end - start), StandardCharsets.US_ASCII), mode); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/ToplevelBlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.eclipse.kura.driver.binary.Buffer; /** *

* Represent a {@link BlockTask} that has a list of child tasks and maintains a {@link Buffer}. *

*

* Each child task operates on a subset of the interval described by this task and generally use the buffer provided by * this class to perform their operation. *

*

* The operation described by a {@link ToplevelBlockTask} generally involves transferring data * between a {@link Buffer} and device. * The children of a {@link ToplevelBlockTask} generally do not perform actual I/O operations but simply use the buffer * managed by an instance of this class by either filling or consuming it depending on the {@link Mode}. In particular: *

*
    *
  • If the {@link Mode} of a {@link ToplevelBlockTask} is {@link Mode#READ} calling the {@link BlockTask#run()} * method of this class will trigger the following operations: *
      *
    1. The {@link ToplevelBlockTask#processBuffer()} method is called, its implementation must fill the {@link Buffer} * of this class with some data, usually obtained performing a read operation from some device.
    2. *
    3. * If previous step completes successfully the {@link BlockTask#run()} method of each children will be called. Each * child will use the data of the {@link Buffer} filled at previous step to perform its operation (for example * extracting some information from it). If the previous step fails the {@link BlockTask#onFailure(Exception)} method of * the children will be called to notify the failure. *
    4. *
    *
  • *
  • If the {@link Mode} of a {@link ToplevelBlockTask} is {@link Mode#WRITE} calling the {@link BlockTask#run()} * method of this class will trigger the following operations: *
      *
    1. * The {@link BlockTask#run()} method of each children will be called. Each * child should fill a portion of the {@link Buffer} of this class. *
    2. *
    3. * The {@link ToplevelBlockTask#processBuffer()} method is called, its implementation should use the {@link Buffer} * previously filled by the children, for example by transferring it to some device. *
    4. *
    5. * If previous step completes successfully the {@link BlockTask#onSuccess()} method of each children will be called. If * the previous step fails the {@link BlockTask#onFailure(Exception)} method of * the children will be called to notify the failure. *
    6. *
    *
  • *
*/ public abstract class ToplevelBlockTask extends BlockTask { private final ArrayList children = new ArrayList<>(); private boolean isAborted; public ToplevelBlockTask(int start, int end, Mode mode) { super(start, end, mode); } /** * Returns the {@link Buffer} managed by this {@link ToplevelBlockTask}. The result must not be null and its size * must be equal to {@code this.getEnd() - this.getStart()} * * @return The {@link Buffer} managed by this {@link ToplevelBlockTask}. */ public abstract Buffer getBuffer(); /** * Performs an operation on the {@link Buffer} managed by this {@link ToplevelBlockTask}. See the class description * for more information on the expected behavior of this method. * * @throws IOException * If some I/O error occur */ public abstract void processBuffer() throws IOException; /** * Clears the list of children of this {@link ToplevelBlockTask} */ public void clear() { this.children.clear(); } /** * Returns the children of this {@link ToplevelBlockTask} as an unmodifiable list. * * @return The children of this task */ public List getChildren() { return Collections.unmodifiableList(this.children); } /** * Invokes the {@link BlockTask#run()} method on the children of this class. * * @throws IOException * If the {@link BlockTask#run()} method of a child throw an {@link IOException} */ protected void runChildren() throws IOException { this.isAborted = false; for (BlockTask child : getChildren()) { child.setParent(this); child.run(); if (this.isAborted) { break; } } } /** * Adds a child to this {@link ToplevelBlockTask} * * @param child * the child to be added. * @throws IllegalArgumentException * if the interval specified by the provided {@link BlockTask} is not contained by the interval * specified by this {@link ToplevelBlockTask} */ public void addChild(BlockTask child) { if (!this.contains(child)) { throw new IllegalArgumentException("The child block must be contained by this block"); } this.children.add(child); } /** * Aborts the operation performed by this {@link ToplevelBlockTask}, it can be called by a child if some * non-recoverable error is detected. The {@link BlockTask#onFailure(Exception)} method of the children will be * called to notify the error. * * @param exception * the reason for which the execution must be aborted. */ public void abort(Exception exception) { this.isAborted = true; onFailure(exception); } /** * {@inheritDoc} */ @Override public void run() throws IOException { try { if (getMode() == Mode.READ) { processBuffer(); runChildren(); } else { runChildren(); processBuffer(); onSuccess(); } } catch (Exception e) { onFailure(e); throw e; } } /** * {@inheritDoc}} */ @Override public void onSuccess() { for (BlockTask child : getChildren()) { child.onSuccess(); } } /** * {@inheritDoc} */ @Override public void onFailure(Exception exception) { for (BlockTask child : getChildren()) { child.onFailure(exception); } } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append(super.toString()); if (!this.children.isEmpty()) { builder.append(" children: "); for (BlockTask b : getChildren()) { builder.append(b.toString()); builder.append(' '); } } return builder.toString(); } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/UpdateBlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import org.eclipse.kura.channel.ChannelRecord; /** *

* This is an helper class that can be used to implement read-update-write operations that involve an same interval of * addresses. An example of such operation can * be reading a block of data from a device, updating that data and then writing it back. *

*

* If an instance of this class is provided as input to a {@link UpdateBlockTaskAggregator}, and its {@link Mode} is * {@link Mode#UPDATE}, it will be assigned to two parent {@link ToplevelBlockTask} instances by the aggregator. * The first {@link ToplevelBlockTask} will provide the data needed by this class for the read part of its operation, * and the second {@link ToplevelBlockTask} can be used by this class to write back the modified data. *

*

* In the scenario above, the {@link BlockTask#run()} method of this class will be called twice, the first time for the * read part of the operation and the second time for the write. Implementors are not required to implement the * {@link BlockTask#run()} method directly but must implement the {@link UpdateBlockTask#runRead()}, * {@link UpdateBlockTask#runWrite())} and {@link UpdateBlockTask#runUpdate(ToplevelBlockTask, ToplevelBlockTask)} * methods instead. See the description of these methods for more information. *

*/ public abstract class UpdateBlockTask extends ChannelBlockTask { private ToplevelBlockTask readParent; public UpdateBlockTask(ChannelRecord record, int start, int end, Mode mode) { super(record, start, end, mode); } /** * Called if the {@link Mode} of this instance is {@link Mode#READ}. This method should behave in the same way as * the {@link BlockTask#run()} method of a normal (non read-update-write) {@link BlockTask} instance in * {@link Mode#READ} mode. */ protected abstract void runRead(); /** * Called if the {@link Mode} of this instance is {@link Mode#WRITE}. This method should behave in the same way as * the {@link BlockTask#run()} method of a normal (non read-update-write) {@link BlockTask} instance in * {@link Mode#WRITE} mode. */ protected abstract void runWrite(); /** *

* Called if the {@link Mode} of this instance is {@link Mode#UPDATE}. The input data required for the operation can * be retrieved from the {@link Buffer} of the {@code read} task, the data should be updated by this method and * then written back to the {@link Buffer} of the {@code write} task. *

*

* If the {@link Mode} of this task is {@link Mode#UPDATE}, the {@link UpdateBlockTask#runRead()} and * {@link UpdateBlockTask#runWrite()} methods of this class will never be called. *

* * @param write * the {@link ToplevelBlockTask} that contains the data for the read part of the read-update-write * operation performed by this class * @param read * the {@link ToplevelBlockTask} that can be used for writing back the data resulting from the * operation performed by this class */ protected abstract void runUpdate(ToplevelBlockTask write, ToplevelBlockTask read); @Override public void run() { if (getMode() == Mode.READ) { runRead(); } else if (getMode() == Mode.WRITE) { runWrite(); } else { final ToplevelBlockTask parent = getParent(); if (parent.getMode() == Mode.READ) { this.readParent = parent; return; } if (this.readParent == null) { parent.abort(new IllegalStateException( "UPDATE requested but read task did not succeed, operation aboreted")); return; } runUpdate(parent, this.readParent); this.readParent = null; } } } ================================================ FILE: kura/org.eclipse.kura.driver.block/src/main/java/org/eclipse/kura/driver/block/task/UpdateBlockTaskAggregator.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.driver.block.task; import static java.util.Objects.requireNonNull; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.kura.driver.block.Block; import org.eclipse.kura.driver.block.BlockFactory; import org.eclipse.kura.driver.block.ProhibitedBlock; /** *

* Represents a specialized version of {@link BlockTaskAggregator} that supports the aggregation of tasks whose * {@link Mode} is {@link Mode#UPDATE}. This class only supports the aggregation of tasks that are either in * {@link Mode#WRITE} or {@link Mode#UPDATE} mode. *

*

*

* If a task whose {@link Mode} is {@link Mode#UPDATE} is found in the input block list, it will be assigned to two * {@link ToplevelBlockTask} instances, both of them will contain the interval specified by the update task. * The first one will operate in {@link Mode#READ}, the second one in {@link Mode#WRITE}. *

*

* If the {@link ToplevelBlockTask} instances described above are executed in sequence, the {@link BlockTask#run()} * method of the update task will be called twice, the first time the parent of the update task will be assigned to the * {@link ToplevelBlockTask} in {@link Mode#READ} mode, the second time it will be assigned to the * {@link ToplevelBlockTask} in {@link Mode#WRITE} mode. *

*

* If a task that operates in {@link Mode#UPDATE} needs to be defined, the * {@link UpdateBlockTask} class should be extended. *

*

* If some tasks in {@link Mode#UPDATE} are found in the input block list, this class will perform two * separate aggregation processes: one for the {@link ToplevelBlockTask} instances required to fetch the data needed for * the read part of the read-update-write operations, and the other for the {@link ToplevelBlockTask} instances required * for the write part. *

* * @see ToplevelBlockTask * @see BlockTask */ public class UpdateBlockTaskAggregator extends BlockTaskAggregator { private final BlockTaskAggregator readTaskAggregator; /** * Creates a new {@link UpdateBlockTaskAggregator} instance * * @param tasks * the list of input tasks * @param readTaskFactory * a {@link BlockFactory} that will be used for creating the {@link ToplevelBlockTask} instances in * {@link Mode#READ} mode * @param writeTaskFactory * a {@link BlockFactory} that will be used for creating the {@link ToplevelBlockTask} instances in * {@link Mode#WRITE} mode * @throws IllegalArgumentException * if any task in {@link Mode#READ} is found in the input task list */ public UpdateBlockTaskAggregator(List tasks, BlockFactory readTaskFactory, BlockFactory writeTaskFactory) { super(tasks, writeTaskFactory); requireNonNull(readTaskFactory, "Read tasks factory cannot be null"); this.readTaskAggregator = createReadTaskAggregator(tasks, readTaskFactory); } private static BlockTaskAggregator createReadTaskAggregator(List tasks, BlockFactory readTaskFactory) { ArrayList updateTasks = tasks.stream().filter(block -> { if (!(block instanceof BlockTask)) { return false; } BlockTask task = (BlockTask) block; if (task.getMode() == Mode.READ) { throw new IllegalArgumentException("Read task are not supported by UpdateBlockTaskAggregator"); } return task.getMode() == Mode.UPDATE; }).collect(Collectors.toCollection(ArrayList::new)); return new BlockTaskAggregator(updateTasks, readTaskFactory); } /** * Sets the {@code minimumGapSize} that will be used for aggregating the {@link ToplevelBlockTask} tasks * in {@link Mode#READ} mode, the {@link ToplevelBlockTask} instances in {@link Mode#WRITE} will always be * aggregated with {@code minimumGapSize = 0}. */ @Override public void setMinimumGapSize(int minimumGapSize) { this.readTaskAggregator.setMinimumGapSize(minimumGapSize); } /** * {@inheritDoc} * * @throws IllegalArgumentException * if the provided task is in {@link Mode#READ} mode. */ @Override public void addBlock(Block block) { boolean isBlockTask = block instanceof BlockTask; if (isBlockTask && ((BlockTask) block).getMode() == Mode.READ) { throw new IllegalArgumentException("Read task are not supported by UpdateBlockTaskAggregator"); } super.addBlock(block); if (block instanceof ProhibitedBlock || isBlockTask && ((BlockTask) block).getMode() == Mode.UPDATE) { this.readTaskAggregator.addBlock(block); } } /** * Returns a {@link Stream} yielding the result of the aggregation. The returned {@link Stream} will produce the * {@link ToplevelBlockTask} instances in {@link Mode#READ} first and then the {@link ToplevelBlockTask} instances * in {@link Mode#WRITE} mode. */ @Override public Stream stream() { return Stream.concat(this.readTaskAggregator.stream(), super.stream()); } } ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/.gitignore ================================================ /bin/ ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Driver Helper Service Provider Bundle-SymbolicName: org.eclipse.kura.driver.helper.provider Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Bundle-License: Eclipse Public License v2.0 Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: org.eclipse.kura.asset;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.driver;version="[1.0,1.1)", org.eclipse.kura.driver.descriptor;version="[1.0,1.1)", org.eclipse.kura.util.collection;version="[1.0,2.0)", org.eclipse.kura.util.service;version="[1.0,2.0)", org.osgi.framework;version="1.8", org.osgi.service.cm;version="1.5.0", org.osgi.service.component;version="1.2.2", org.slf4j;version="1.6.4" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/OSGI-INF/DriverDescriptorComponent.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/OSGI-INF/DriverServiceComponent.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/build.properties ================================================ # # Copyright (c) 2016, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # Amit Kumar Mondal # source.. = src/main/java/ src.includes = about.html bin.includes = META-INF/,\ .,\ about.html,\ OSGI-INF/ additional.bundles = org.eclipse.osgi ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.driver.helper.provider 2.0.0-SNAPSHOT eclipse-plugin ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.driver.helper.test/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/src/main/java/org/eclipse/kura/internal/driver/DriverDescriptorServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2018, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.driver; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID; import static org.osgi.service.cm.ConfigurationAdmin.SERVICE_FACTORYPID; import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.eclipse.kura.driver.Driver; import org.eclipse.kura.driver.descriptor.DriverDescriptor; import org.eclipse.kura.driver.descriptor.DriverDescriptorService; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class DriverDescriptorServiceImpl implements DriverDescriptorService { private static final Logger logger = LoggerFactory.getLogger(DriverDescriptorServiceImpl.class); private BundleContext bundleContext; public void activate(ComponentContext componentContext) { this.bundleContext = componentContext.getBundleContext(); } @Override public Optional getDriverDescriptor(String driverPid) { requireNonNull(driverPid, "Driver PID cannot be null"); DriverDescriptor driverDescriptor = null; String filterString = String.format("(&(kura.service.pid=%s))", driverPid); final ServiceReference[] refs = getDriverServiceReferences(filterString); try { for (final ServiceReference driverServiceReference : refs) { String factoryPid = driverServiceReference.getProperty(SERVICE_FACTORYPID).toString(); Driver driver = this.bundleContext.getService(driverServiceReference); driverDescriptor = newDriverDescriptor(driverPid, factoryPid, driver); } } finally { ungetDriverServiceReferences(refs); } return Optional.ofNullable(driverDescriptor); } @Override public List listDriverDescriptors() { List driverDescriptors = new ArrayList<>(); final ServiceReference[] refs = getDriverServiceReferences(null); try { for (final ServiceReference driverServiceReference : refs) { String driverPid = driverServiceReference.getProperty(KURA_SERVICE_PID).toString(); String factoryPid = driverServiceReference.getProperty(SERVICE_FACTORYPID).toString(); Driver driver = this.bundleContext.getService(driverServiceReference); driverDescriptors.add(newDriverDescriptor(driverPid, factoryPid, driver)); } } finally { ungetDriverServiceReferences(refs); } return driverDescriptors; } private DriverDescriptor newDriverDescriptor(String driverPid, String factoryPid, Driver driver) { Object channelDescriptorObj = null; try { channelDescriptorObj = driver.getChannelDescriptor().getDescriptor(); } catch (Exception e) { logger.warn("Failed to get driver descriptor for pid: {}", driverPid, e); } return new DriverDescriptor(driverPid, factoryPid, channelDescriptorObj); } protected ServiceReference[] getDriverServiceReferences(final String filter) { return ServiceUtil.getServiceReferences(this.bundleContext, Driver.class, filter); } protected void ungetDriverServiceReferences(final ServiceReference[] refs) { ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } } ================================================ FILE: kura/org.eclipse.kura.driver.helper.provider/src/main/java/org/eclipse/kura/internal/driver/DriverServiceImpl.java ================================================ /******************************************************************************* * Copyright (c) 2016, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Red Hat Inc *******************************************************************************/ package org.eclipse.kura.internal.driver; import static java.util.Objects.requireNonNull; import static org.eclipse.kura.driver.Driver.DRIVER_PID_PROPERTY_NAME; import java.util.ArrayList; import java.util.List; import org.eclipse.kura.driver.Driver; import org.eclipse.kura.driver.DriverService; import org.eclipse.kura.util.service.ServiceUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; /** * The Class DriverServiceImpl is an implementation of the utility API * {@link DriverService} to provide useful factory methods for drivers */ public class DriverServiceImpl implements DriverService { private BundleContext bundleContext; public void activate(ComponentContext componentContext) { this.bundleContext = componentContext.getBundleContext(); } /** {@inheritDoc} */ @Override public Driver getDriver(final String driverPid) { requireNonNull(driverPid, "Driver PID cannot be null"); Driver driver = null; String filterString = String.format("(&(kura.service.pid=%s))", driverPid); final ServiceReference[] refs = getDriverServiceReferences(filterString); try { for (final ServiceReference ref : refs) { driver = this.bundleContext.getService(ref); } } finally { ungetDriverServiceReferences(refs); } return driver; } /** {@inheritDoc} */ @Override public String getDriverPid(final Driver driver) { requireNonNull(driver, "Driver PID cannot be null"); final ServiceReference[] refs = getDriverServiceReferences(null); try { for (final ServiceReference ref : refs) { final Driver driverRef = this.bundleContext.getService(ref); if (driverRef == driver) { return ref.getProperty(DRIVER_PID_PROPERTY_NAME).toString(); } } } finally { ungetDriverServiceReferences(refs); } return null; } /** {@inheritDoc} */ @Override public List listDrivers() { final List drivers = new ArrayList<>(); final ServiceReference[] refs = getDriverServiceReferences(null); try { for (final ServiceReference ref : refs) { final Driver driverRef = this.bundleContext.getService(ref); drivers.add(driverRef); } } finally { ungetDriverServiceReferences(refs); } return drivers; } protected ServiceReference[] getDriverServiceReferences(final String filter) { return ServiceUtil.getServiceReferences(this.bundleContext, Driver.class, filter); } protected void ungetDriverServiceReferences(final ServiceReference[] refs) { ServiceUtil.ungetServiceReferences(this.bundleContext, refs); } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/.gitignore ================================================ /dp/ ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: S7 PLC Communication Driver Bundle-SymbolicName: org.eclipse.kura.driver.s7plc.provider;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: Eclipse Kura Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Import-Package: Moka7;version="[1.0,1.1)", org.eclipse.kura;version="[1.2,2.0)", org.eclipse.kura.channel;version="[1.0,2.0)", org.eclipse.kura.channel.listener;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.1,2.0)", org.eclipse.kura.configuration.metatype;version="[1.0,2.0)", org.eclipse.kura.core.configuration.metatype;version="[1.0,2.0)", org.eclipse.kura.crypto;version="[1.2,2.0)", org.eclipse.kura.driver;version="[1.0,1.1)", org.eclipse.kura.type;version="[1.0,2.0)", org.eclipse.kura.util.base;version="[1.0,2.0)", org.eclipse.kura.util.collection;version="[1.0,2.0)", org.osgi.service.component;version="1.2.0", org.slf4j;version="1.6.4" Bundle-ActivationPolicy: lazy Service-Component: OSGI-INF/*.xml Bundle-ClassPath: ., lib/org.eclipse.kura.driver.block.jar ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/OSGI-INF/S7PlcDriverComponent.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/OSGI-INF/metatype/org.eclipse.kura.driver.s7plc.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/about_files/epl-v20.html ================================================ Eclipse Public License - Version 2.0

Eclipse Public License - v 2.0

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (“AGREEMENT”). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

1. DEFINITIONS

“Contribution” means:

  • a) in the case of the initial Contributor, the initial content Distributed under this Agreement, and
  • b) in the case of each subsequent Contributor:
    • i) changes to the Program, and
    • ii) additions to the Program;
    where such changes and/or additions to the Program originate from and are Distributed by that particular Contributor. A Contribution “originates” from a Contributor if it was added to the Program by such Contributor itself or anyone acting on such Contributor's behalf. Contributions do not include changes or additions to the Program that are not Modified Works.

“Contributor” means any person or entity that Distributes the Program.

“Licensed Patents” mean patent claims licensable by a Contributor which are necessarily infringed by the use or sale of its Contribution alone or when combined with the Program.

“Program” means the Contributions Distributed in accordance with this Agreement.

“Recipient” means anyone who receives the Program under this Agreement or any Secondary License (as applicable), including Contributors.

“Derivative Works” shall mean any work, whether in Source Code or other form, that is based on (or derived from) the Program and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship.

“Modified Works” shall mean any work in Source Code or other form that results from an addition to, deletion from, or modification of the contents of the Program, including, for purposes of clarity any new file in Source Code form that contains any contents of the Program. Modified Works shall not include works that contain only declarations, interfaces, types, classes, structures, or files of the Program solely in each case in order to link to, bind by name, or subclass the Program or Modified Works thereof.

“Distribute” means the acts of a) distributing or b) making available in any manner that enables the transfer of a copy.

“Source Code” means the form of a Program preferred for making modifications, including but not limited to software source code, documentation source, and configuration files.

“Secondary License” means either the GNU General Public License, Version 2.0, or any later versions of that license, including any exceptions or additional permissions as identified by the initial Contributor.

2. GRANT OF RIGHTS

  • a) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, Distribute and sublicense the Contribution of such Contributor, if any, and such Derivative Works.
  • b) Subject to the terms of this Agreement, each Contributor hereby grants Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Contribution of such Contributor, if any, in Source Code or other form. This patent license shall apply to the combination of the Contribution and the Program if, at the time the Contribution is added by the Contributor, such addition of the Contribution causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Contribution. No hardware per se is licensed hereunder.
  • c) Recipient understands that although each Contributor grants the licenses to its Contributions set forth herein, no assurances are provided by any Contributor that the Program does not infringe the patent or other intellectual property rights of any other entity. Each Contributor disclaims any liability to Recipient for claims brought by any other entity based on infringement of intellectual property rights or otherwise. As a condition to exercising the rights and licenses granted hereunder, each Recipient hereby assumes sole responsibility to secure any other intellectual property rights needed, if any. For example, if a third party patent license is required to allow Recipient to Distribute the Program, it is Recipient's responsibility to acquire that license before distributing the Program.
  • d) Each Contributor represents that to its knowledge it has sufficient copyright rights in its Contribution, if any, to grant the copyright license set forth in this Agreement.
  • e) Notwithstanding the terms of any Secondary License, no Contributor makes additional grants to any Recipient (other than those set forth in this Agreement) as a result of such Recipient's receipt of the Program under the terms of a Secondary License (if permitted under the terms of Section 3).

3. REQUIREMENTS

3.1 If a Contributor Distributes the Program in any form, then:

  • a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
  • b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
    • i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
    • ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
    • iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
    • iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.

3.2 When the Program is Distributed as Source Code:

  • a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
  • b) a copy of this Agreement must be included with each copy of the Program.

3.3 Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.

4. COMMERCIAL DISTRIBUTION

Commercial distributors of software may accept certain responsibilities with respect to end users, business partners and the like. While this license is intended to facilitate the commercial use of the Program, the Contributor who includes the Program in a commercial product offering should do so in a manner which does not create potential liability for other Contributors. Therefore, if a Contributor includes the Program in a commercial product offering, such Contributor (“Commercial Contributor”) hereby agrees to defend and indemnify every other Contributor (“Indemnified Contributor”) against any losses, damages and costs (collectively “Losses”) arising from claims, lawsuits and other legal actions brought by a third party against the Indemnified Contributor to the extent caused by the acts or omissions of such Commercial Contributor in connection with its distribution of the Program in a commercial product offering. The obligations in this section do not apply to any claims or Losses relating to any actual or alleged intellectual property infringement. In order to qualify, an Indemnified Contributor must: a) promptly notify the Commercial Contributor in writing of such claim, and b) allow the Commercial Contributor to control, and cooperate with the Commercial Contributor in, the defense and any related settlement negotiations. The Indemnified Contributor may participate in any such claim at its own expense.

For example, a Contributor might include the Program in a commercial product offering, Product X. That Contributor is then a Commercial Contributor. If that Commercial Contributor then makes performance claims, or offers warranties related to Product X, those performance claims and warranties are such Commercial Contributor's responsibility alone. Under this section, the Commercial Contributor would have to defend claims against the other Contributors related to those performance claims and warranties, and if a court requires any other Contributor to pay any damages as a result, the Commercial Contributor must pay those damages.

5. NO WARRANTY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely responsible for determining the appropriateness of using and distributing the Program and assumes all risks associated with its exercise of rights under this Agreement, including but not limited to the risks and costs of program errors, compliance with applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations.

6. DISCLAIMER OF LIABILITY

EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. GENERAL

If any provision of this Agreement is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this Agreement, and without further action by the parties hereto, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable.

If Recipient institutes patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Program itself (excluding combinations of the Program with other software or hardware) infringes such Recipient's patent(s), then such Recipient's rights granted under Section 2(b) shall terminate as of the date such litigation is filed.

All Recipient's rights under this Agreement shall terminate if it fails to comply with any of the material terms or conditions of this Agreement and does not cure such failure in a reasonable period of time after becoming aware of such noncompliance. If all Recipient's rights under this Agreement terminate, Recipient agrees to cease use and distribution of the Program as soon as reasonably practicable. However, Recipient's obligations under this Agreement and any licenses granted by Recipient relating to the Program shall continue and survive.

Everyone is permitted to copy and distribute copies of this Agreement, but in order to avoid inconsistency the Agreement is copyrighted and may only be modified in the following manner. The Agreement Steward reserves the right to publish new versions (including revisions) of this Agreement from time to time. No one other than the Agreement Steward has the right to modify this Agreement. The Eclipse Foundation is the initial Agreement Steward. The Eclipse Foundation may assign the responsibility to serve as the Agreement Steward to a suitable separate entity. Each new version of the Agreement will be given a distinguishing version number. The Program (including Contributions) may always be Distributed subject to the version of the Agreement under which it was received. In addition, after a new version of the Agreement is published, Contributor may elect to Distribute the Program (including its Contributions) under the new version.

Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to the intellectual property of any Contributor under this Agreement, whether expressly, by implication, estoppel or otherwise. All rights in the Program not expressly granted under this Agreement are reserved. Nothing in this Agreement is intended to be enforceable by any entity that is not a Contributor or Recipient. No third-party beneficiary rights are created under this Agreement.

Exhibit A – Form of Secondary Licenses Notice

“This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), version(s), and exceptions or additional permissions here}.”

Simply including a copy of this Agreement, including this Exhibit A is not sufficient to license the Source Code under Secondary Licenses.

If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice.

You may add additional accurate notices of copyright ownership.

================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/build.properties ================================================ source.. = src/main/java/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ lib/,\ lib/org.eclipse.kura.driver.block.jar,\ about.html,\ about_files/ ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/lib/.gitignore ================================================ /*.jar ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.driver.s7plc.provider 2.0.0-SNAPSHOT eclipse-plugin 1.0.0 ${project.basedir}/.. ${project.basedir}/../test/org.eclipse.kura.internal.driver.s7plc.test/target/site/jacoco-aggregate/jacoco.xml org.eclipse.kura org.eclipse.kura.driver.block ${optimizer.version} maven-dependency-plugin 3.8.1 copy-dependencies generate-sources copy-dependencies ${project.build.directory} org.eclipse.kura.driver.block false org.apache.maven.plugins maven-antrun-plugin 1.8 generate-sources copy-optimizer-jar run clean clean-optimizer-jar run ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcChannelDescriptor.java ================================================ /** * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal (admin@amitinside.com) */ package org.eclipse.kura.internal.driver.s7plc; import java.util.List; import org.eclipse.kura.core.configuration.metatype.Tad; import org.eclipse.kura.core.configuration.metatype.Toption; import org.eclipse.kura.core.configuration.metatype.Tscalar; import org.eclipse.kura.driver.ChannelDescriptor; import org.eclipse.kura.util.collection.CollectionUtil; /** * S7 PLC specific channel descriptor. The descriptor contains the following * attribute definition identifiers. * *
    *
  • area.no
  • denotes the Area Number *
  • offset
  • the offset *
  • byte.count
  • the number of bytes to read *
*/ public final class S7PlcChannelDescriptor implements ChannelDescriptor { public static final String S7_ELEMENT_TYPE_ID = "s7.data.type"; public static final String DATA_BLOCK_NO_ID = "data.block.no"; public static final String BYTE_COUNT_ID = "byte.count"; public static final String OFFSET_ID = "offset"; public static final String BIT_INDEX_ID = "bit.index"; private Toption generateOption(S7PlcDataType type) { Toption option = new Toption(); option.setLabel(type.name()); option.setValue(type.name()); return option; } /** {@inheritDoc} */ @Override public Object getDescriptor() { final List elements = CollectionUtil.newArrayList(); final Tad s7ElementType = new Tad(); s7ElementType.setName(S7_ELEMENT_TYPE_ID); s7ElementType.setId(S7_ELEMENT_TYPE_ID); s7ElementType.setDescription("S7 Data Type"); s7ElementType.setType(Tscalar.STRING); s7ElementType.setRequired(true); s7ElementType.setDefault(S7PlcDataType.INT.name()); for (S7PlcDataType t : S7PlcDataType.values()) { s7ElementType.setOption(generateOption(t)); } elements.add(s7ElementType); final Tad areaNo = new Tad(); areaNo.setName(DATA_BLOCK_NO_ID); areaNo.setId(DATA_BLOCK_NO_ID); areaNo.setDescription("DB number"); areaNo.setType(Tscalar.INTEGER); areaNo.setRequired(true); areaNo.setDefault("0"); elements.add(areaNo); final Tad offset = new Tad(); offset.setName(OFFSET_ID); offset.setId(OFFSET_ID); offset.setDescription("offset"); offset.setType(Tscalar.INTEGER); offset.setRequired(true); offset.setDefault("0"); elements.add(offset); final Tad byteCount = new Tad(); byteCount.setName(BYTE_COUNT_ID); byteCount.setId(BYTE_COUNT_ID); byteCount.setDescription("Byte Count"); byteCount.setType(Tscalar.INTEGER); byteCount.setRequired(true); byteCount.setDefault("0"); elements.add(byteCount); final Tad bitIndex = new Tad(); bitIndex.setName(BIT_INDEX_ID); bitIndex.setId(BIT_INDEX_ID); bitIndex.setDescription("Bit Index"); bitIndex.setType(Tscalar.INTEGER); bitIndex.setRequired(true); bitIndex.setMin("0"); bitIndex.setMax("7"); bitIndex.setDefault("0"); elements.add(bitIndex); return elements; } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDataType.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.driver.s7plc; public enum S7PlcDataType { BOOL, BYTE, WORD, DWORD, INT, DINT, REAL, CHAR } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDomain.java ================================================ /** * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech */ package org.eclipse.kura.internal.driver.s7plc; public class S7PlcDomain { private final int db; public S7PlcDomain(int db) { this.db = db; } public int getDB() { return this.db; } @Override public int hashCode() { return this.db; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } S7PlcDomain other = (S7PlcDomain) obj; if (this.db != other.db) { return false; } return true; } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcDriver.java ================================================ /** * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech */ package org.eclipse.kura.internal.driver.s7plc; import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Stream; import org.eclipse.kura.KuraException; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.crypto.CryptoService; import org.eclipse.kura.driver.ChannelDescriptor; import org.eclipse.kura.driver.block.BlockFactory; import org.eclipse.kura.driver.block.task.AbstractBlockDriver; import org.eclipse.kura.driver.block.task.BlockTask; import org.eclipse.kura.driver.block.task.Mode; import org.eclipse.kura.driver.block.task.ToplevelBlockTask; import org.eclipse.kura.internal.driver.s7plc.task.S7PlcTaskBuilder; import org.eclipse.kura.internal.driver.s7plc.task.S7PlcToplevelBlockTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import Moka7.S7; import Moka7.S7Client; /** * The Kura S7PlcDriver is a S7 PLC Driver implementation for Kura Asset-Driver * Topology.
*
* * The Kura S7 PLC Driver can be used in cooperation with Kura Asset Model and in * isolation as well. In case of isolation, the properties needs to be provided * externally.
*
* * The required properties are enlisted in {@link S7PlcChannelDescriptor} and * the driver connection specific properties are enlisted in * {@link S7PlcOptions} * * @see S7PlcChannelDescriptor * @see S7PlcOptions */ public class S7PlcDriver extends AbstractBlockDriver implements ConfigurableComponent { private static final Logger logger = LoggerFactory.getLogger(S7PlcDriver.class); private S7ClientState state = new S7ClientState(new S7PlcOptions(Collections.emptyMap())); private final AtomicReference options = new AtomicReference<>(); private CryptoService cryptoService; public void setCryptoService(CryptoService cryptoService) { this.cryptoService = cryptoService; } public void unsetCryptoService() { this.cryptoService = null; } public void activate(final Map properties) { logger.debug("Activating S7 PLC Driver..."); updated(properties); logger.debug("Activating S7 PLC Driver... Done"); } public synchronized void deactivate() { logger.debug("Deactivating S7 PLC Driver..."); try { disconnect(); } catch (final ConnectionException e) { logger.error("Error while disconnecting...", e); } logger.debug("Deactivating S7 PLC Driver.....Done"); } public void updated(final Map properties) { logger.debug("Updating S7 PLC Driver..."); this.options.set(new S7PlcOptions(properties)); logger.debug("Updating S7 PLC Driver... Done"); } private String decryptPassword(char[] encryptedPassword) throws KuraException { final char[] decodedPasswordChars = this.cryptoService.decryptAes(encryptedPassword); return new String(decodedPasswordChars); } private void authenticate(final S7ClientState state) throws ConnectionException { logger.debug("Authenticating"); int code; try { code = state.client.SetSessionPassword(decryptPassword(state.options.getPassword().toCharArray())); } catch (Exception e) { throw new ConnectionException(e); } if (code != 0) { throw new ConnectionException("Authentication failed, SetSessionPassword() failed with code: " + code); } } @Override public synchronized void connect() throws ConnectionException { try { final S7PlcOptions currentOptions = this.options.get(); if (this.state.options != currentOptions) { logger.info("configuration changed, disconnecting..."); disconnect(); this.state = createClientState(currentOptions); logger.info("configuration changed, disconnecting...Done"); } if (!this.state.client.Connected) { logger.debug("Connecting to S7 PLC..."); this.state.client.SetConnectionType(S7.OP); int code = this.state.client.ConnectTo(currentOptions.getIp(), currentOptions.getRack(), currentOptions.getSlot()); if (code != 0) { throw new ConnectionException("Failed to connect to PLC, ConnectTo() failed with code: " + code); } if (currentOptions.shouldAuthenticate()) { authenticate(this.state); } logger.debug("Connecting to S7 PLC... Done"); } } catch (Exception e) { throw new ConnectionException("Connection failed, unexpected exception", e); } } @Override public synchronized void disconnect() throws ConnectionException { if (this.state.client.Connected) { logger.debug("Disconnecting from S7 PLC..."); this.state.client.Disconnect(); logger.debug("Disconnecting from S7 PLC... Done"); } } @Override protected int getReadMinimumGapSizeForDomain(S7PlcDomain domain) { return this.options.get().getMinimumGapSize(); } @Override protected BlockFactory getTaskFactoryForDomain(final S7PlcDomain domain, final Mode mode) { return (start, end) -> new S7PlcToplevelBlockTask(S7PlcDriver.this, mode, domain.getDB(), start, end); } @Override protected Stream> toTasks(List records, Mode mode) { return S7PlcTaskBuilder.build(records, mode); } @Override public ChannelDescriptor getChannelDescriptor() { return new S7PlcChannelDescriptor(); } protected S7ClientState createClientState(final S7PlcOptions options) { return new S7ClientState(options); } @Override protected void runTask(BlockTask task) { try { task.run(); } catch (Moka7Exception e) { handleMoka7IOException(e); } catch (Exception e) { logger.warn("Unexpected exception", e); } } private void handleMoka7IOException(Moka7Exception e) { logger.warn("Operation failed due to IO error", e); if (e.getStatusCode() <= S7Client.errTCPConnectionReset) { logger.warn("Connection problems detected, disconnecting, will attempt to reconnect at next read/write"); try { disconnect(); } catch (ConnectionException e1) { logger.warn("Unable to Disconnect...", e1); } } } public synchronized void write(int db, int offset, byte[] data) throws IOException { int result = this.state.client.WriteArea(S7.S7AreaDB, db, offset, data.length, data); if (result != 0) { throw new Moka7Exception("DB: " + db + " off: " + offset + " len: " + data.length + " status: " + result, result); } } public synchronized void read(int db, int offset, byte[] data) throws IOException { int result = this.state.client.ReadArea(S7.S7AreaDB, db, offset, data.length, data); if (result != 0) { throw new Moka7Exception("DB: " + db + " off: " + offset + " len: " + data.length + " status: " + result, result); } } @SuppressWarnings("serial") static final class Moka7Exception extends IOException { /** * */ private static final long serialVersionUID = -6118257067654374279L; private final int statusCode; public Moka7Exception(String message, int statusCode) { super(message); this.statusCode = statusCode; } public int getStatusCode() { return this.statusCode; } } static final class S7ClientState { private final S7Client client; private final S7PlcOptions options; S7ClientState(final S7PlcOptions options) { this(options, new S7Client()); } public S7ClientState(final S7PlcOptions options, final S7Client client) { this.options = options; this.client = client; } } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/S7PlcOptions.java ================================================ /** * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech * Amit Kumar Mondal (admin@amitinside.com) */ package org.eclipse.kura.internal.driver.s7plc; import java.util.Map; final class S7PlcOptions { private static final Property IP_PROP = new Property<>("host.ip", ""); private static final Property AUTENTICATE_PROP = new Property<>("authenticate", false); private static final Property PASSWORD_PROP = new Property<>("password", ""); private static final Property RACK_PROP = new Property<>("rack", 0); private static final Property SLOT_PROP = new Property<>("slot", 2); private static final Property MINIMUM_GAP_SIZE_PROP = new Property<>("read.minimum.gap.size", 0); private final String ip; private final boolean authenticate; private final String password; private final int rack; private final int slot; private final int minimumGapSize; S7PlcOptions(final Map properties) { this.ip = IP_PROP.get(properties); this.authenticate = AUTENTICATE_PROP.get(properties); this.password = PASSWORD_PROP.get(properties); this.rack = RACK_PROP.get(properties); this.slot = SLOT_PROP.get(properties); this.minimumGapSize = MINIMUM_GAP_SIZE_PROP.get(properties); } String getIp() { return this.ip; } boolean shouldAuthenticate() { return this.authenticate; } String getPassword() { return this.password; } int getRack() { return this.rack; } int getSlot() { return this.slot; } int getMinimumGapSize() { return this.minimumGapSize; } private static class Property { private final String key; private final T defaultValue; public Property(String key, T defaultValue) { this.key = key; this.defaultValue = defaultValue; } @SuppressWarnings("unchecked") public T get(Map properties) { final Object value = properties.get(this.key); if (this.defaultValue.getClass().isInstance(value)) { return (T) value; } return this.defaultValue; } } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcTaskBuilder.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.driver.s7plc.task; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Stream; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.channel.ChannelFlag; import org.eclipse.kura.channel.ChannelRecord; import org.eclipse.kura.channel.ChannelStatus; import org.eclipse.kura.driver.binary.BinaryDataTypes; import org.eclipse.kura.driver.block.task.AbstractBlockDriver.Pair; import org.eclipse.kura.driver.block.task.BinaryDataTask; import org.eclipse.kura.driver.block.task.BitTask; import org.eclipse.kura.driver.block.task.BlockTask; import org.eclipse.kura.driver.block.task.ByteArrayTask; import org.eclipse.kura.driver.block.task.Mode; import org.eclipse.kura.driver.block.task.StringTask; import org.eclipse.kura.internal.driver.s7plc.S7PlcChannelDescriptor; import org.eclipse.kura.internal.driver.s7plc.S7PlcDataType; import org.eclipse.kura.internal.driver.s7plc.S7PlcDomain; import org.eclipse.kura.type.DataType; public final class S7PlcTaskBuilder { private S7PlcTaskBuilder() { } private static int getAreaNo(ChannelRecord record) throws KuraException { try { return getIntProperty(record, S7PlcChannelDescriptor.DATA_BLOCK_NO_ID, "Error while retrieving Area No"); } catch (KuraException e) { record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e)); record.setTimestamp(System.currentTimeMillis()); throw e; } } private static int getIntProperty(ChannelRecord record, String propertyName, String failureMessage) throws KuraException { try { return Integer.parseInt(record.getChannelConfig().get(propertyName).toString()); } catch (Exception e) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, failureMessage); } } private static void assertChannelType(ChannelRecord record, DataType channelType) throws KuraException { if (channelType != record.getValueType()) { throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, "Channel Value Type must be " + channelType); } } private static BlockTask build(ChannelRecord record, Mode mode) throws KuraException { final Map channelConfig = record.getChannelConfig(); DataType type = record.getValueType(); int offset = getIntProperty(record, S7PlcChannelDescriptor.OFFSET_ID, "Error while retrieving Area Offset"); String s7DataTypeId = (String) channelConfig.get(S7PlcChannelDescriptor.S7_ELEMENT_TYPE_ID); if (type == DataType.BYTE_ARRAY) { int byteCount = getIntProperty(record, S7PlcChannelDescriptor.BYTE_COUNT_ID, "Error while retrieving Byte Count"); return new ByteArrayTask(record, offset, offset + byteCount, mode); } else if (S7PlcDataType.INT.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.INT16_BE, type, mode); } else if (S7PlcDataType.DINT.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.INT32_BE, type, mode); } else if (S7PlcDataType.BOOL.name().equals(s7DataTypeId)) { assertChannelType(record, DataType.BOOLEAN); int bitIndex = getIntProperty(record, S7PlcChannelDescriptor.BIT_INDEX_ID, "Error while retreiving bit index"); return new BitTask(record, offset, bitIndex, mode == Mode.WRITE ? Mode.UPDATE : Mode.READ); } else if (S7PlcDataType.WORD.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT16_BE, type, mode); } else if (S7PlcDataType.DWORD.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT32_BE, type, mode); } else if (S7PlcDataType.BYTE.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.UINT8, type, mode); } else if (S7PlcDataType.CHAR.name().equals(s7DataTypeId)) { assertChannelType(record, DataType.STRING); int byteCount = getIntProperty(record, S7PlcChannelDescriptor.BYTE_COUNT_ID, "Error while retrieving Byte Count"); return new StringTask(record, offset, offset + byteCount, mode); } else if (S7PlcDataType.REAL.name().equals(s7DataTypeId)) { return new BinaryDataTask<>(record, offset, BinaryDataTypes.FLOAT_BE, type, mode); } throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, "Unable to determine operation"); } public static Stream> build(List records, Mode mode) { return records.stream().map((record) -> { try { final int db = S7PlcTaskBuilder.getAreaNo(record); return new Pair<>(new S7PlcDomain(db), build(record, mode)); } catch (Exception e) { record.setTimestamp(System.currentTimeMillis()); record.setChannelStatus(new ChannelStatus(ChannelFlag.FAILURE, e.getMessage(), e)); return null; } }).filter(Objects::nonNull); } } ================================================ FILE: kura/org.eclipse.kura.driver.s7plc.provider/src/main/java/org/eclipse/kura/internal/driver/s7plc/task/S7PlcToplevelBlockTask.java ================================================ /******************************************************************************* * Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.internal.driver.s7plc.task; import java.io.IOException; import org.eclipse.kura.driver.binary.Buffer; import org.eclipse.kura.driver.binary.ByteArrayBuffer; import org.eclipse.kura.driver.block.task.Mode; import org.eclipse.kura.driver.block.task.ToplevelBlockTask; import org.eclipse.kura.internal.driver.s7plc.S7PlcDriver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class S7PlcToplevelBlockTask extends ToplevelBlockTask { private static final Logger logger = LoggerFactory.getLogger(S7PlcDriver.class); private final int areaNo; private ByteArrayBuffer data; private final S7PlcDriver driver; public S7PlcToplevelBlockTask(S7PlcDriver driver, Mode mode, int dbNumber, int start, int end) { super(start, end, mode); this.areaNo = dbNumber; this.driver = driver; } @Override public void processBuffer() throws IOException { if (getMode() == Mode.READ) { logger.debug("Reading from PLC, DB{} offset: {} length: {}", this.areaNo, getStart(), getBuffer().getLength()); this.driver.read(this.areaNo, getStart(), ((ByteArrayBuffer) getBuffer()).getBackingArray()); } else { logger.debug("Writing to PLC, DB{} offset: {} length: {}", this.areaNo, getStart(), getBuffer().getLength()); this.driver.write(this.areaNo, getStart(), ((ByteArrayBuffer) getBuffer()).getBackingArray()); } } @Override public Buffer getBuffer() { if (this.data == null) { this.data = new ByteArrayBuffer(new byte[getEnd() - getStart()]); } return this.data; } } ================================================ FILE: kura/org.eclipse.kura.event.publisher/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Event Publisher Bundle-SymbolicName: org.eclipse.kura.event.publisher;singleton:=true Bundle-Version: 2.0.0.qualifier Bundle-Vendor: EUROTECH Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Bundle-ActivationPolicy: lazy Import-Package: org.eclipse.kura;version="[1.0,2.0)", org.eclipse.kura.cloudconnection;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.listener;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.message;version="[1.0,2.0)", org.eclipse.kura.cloudconnection.publisher;version="[1.0,2.0)", org.eclipse.kura.configuration;version="[1.0,2.0)", org.eclipse.kura.util.configuration;version="[1.0.0,2.0.0)", org.osgi.framework;version="1.8.0", org.osgi.service.component;version="1.2.0", org.osgi.util.tracker;version="1.5.1", org.slf4j;version="1.6.4" Bundle-ClassPath: . ================================================ FILE: kura/org.eclipse.kura.event.publisher/OSGI-INF/metatype/org.eclipse.kura.event.publisher.EventPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.event.publisher/OSGI-INF/org.eclipse.kura.event.publisher.EventPublisher.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.event.publisher/build.properties ================================================ ############################################################################### # Copyright (c) 2022 Eurotech and/or its affiliates. All rights reserved. ############################################################################### source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/ ================================================ FILE: kura/org.eclipse.kura.event.publisher/pom.xml ================================================ 4.0.0 org.eclipse.kura.event.publisher eclipse-plugin 2.0.0-SNAPSHOT org.eclipse.kura kura 6.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisher.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher; import static org.eclipse.kura.event.publisher.EventPublisherConstants.CONTROL; import static org.eclipse.kura.event.publisher.EventPublisherConstants.FULL_TOPIC; import static org.eclipse.kura.event.publisher.EventPublisherConstants.PRIORITY; import static org.eclipse.kura.event.publisher.EventPublisherConstants.QOS; import static org.eclipse.kura.event.publisher.EventPublisherConstants.RETAIN; import static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_ACCOUNT_TOKEN; import static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_CLIENT_ID_TOKEN; import static org.eclipse.kura.event.publisher.EventPublisherConstants.TOPIC_SEPARATOR; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.listener.CloudConnectionListener; import org.eclipse.kura.cloudconnection.listener.CloudDeliveryListener; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; import org.eclipse.kura.configuration.ConfigurableComponent; import org.eclipse.kura.event.publisher.helper.CloudEndpointServiceHelper; import org.osgi.framework.BundleContext; import org.osgi.service.component.ComponentContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class EventPublisher implements CloudPublisher, ConfigurableComponent, CloudConnectionListener, CloudDeliveryListener { private static final Logger logger = LoggerFactory.getLogger(EventPublisher.class); private static final String TOPIC_PATTERN_STRING = "\\$([^\\s/]+)"; private static final Pattern TOPIC_PATTERN = Pattern.compile(TOPIC_PATTERN_STRING); private BundleContext bundleContext; private Set cloudDeliveryListeners = new HashSet<>(); private Set cloudConnectionListeners = new HashSet<>(); private EventPublisherOptions options; private final ExecutorService worker = Executors.newCachedThreadPool(); private CloudEndpointServiceHelper cloudHelper; /* * Activation APIs */ public void activate(ComponentContext componentContext, Map properties) { logger.debug("Activating ConfigurationChangePublisher..."); this.bundleContext = componentContext.getBundleContext(); updated(properties); logger.debug("Activating ConfigurationChangePublisher... Done."); } public void updated(Map properties) { logger.debug("Updating ConfigurationChangePublisher..."); this.options = new EventPublisherOptions(properties); this.cloudHelper = new CloudEndpointServiceHelper(this.bundleContext, this.options.getCloudEndpointPid()); logger.debug("Updating ConfigurationChangePublisher... Done."); } public void deactivate(ComponentContext componentContext) { logger.debug("Deactivating ConfigurationChangePublisher..."); this.cloudHelper.close(); logger.debug("Deactivating ConfigurationChangePublisher... Done."); } /* * CloudPublisher APIs */ @Override public String publish(KuraMessage message) throws KuraException { if (message == null) { throw new IllegalArgumentException("Kura message cannot be null"); } String resolvedAppTopic = fillAppTopicPlaceholders(this.options.getTopic(), message); String fullTopic = encodeFullTopic(resolvedAppTopic); Map publishMessageProps = new HashMap<>(); publishMessageProps.put(FULL_TOPIC, fullTopic); publishMessageProps.put(QOS, this.options.getQos()); publishMessageProps.put(RETAIN, this.options.isRetain()); publishMessageProps.put(PRIORITY, this.options.getPriority()); publishMessageProps.put(CONTROL, true); return this.cloudHelper.publish(new KuraMessage(message.getPayload(), publishMessageProps)); } @Override public void registerCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.add(cloudConnectionListener); } @Override public void unregisterCloudConnectionListener(CloudConnectionListener cloudConnectionListener) { this.cloudConnectionListeners.remove(cloudConnectionListener); } @Override public void registerCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.add(cloudDeliveryListener); } @Override public void unregisterCloudDeliveryListener(CloudDeliveryListener cloudDeliveryListener) { this.cloudDeliveryListeners.remove(cloudDeliveryListener); } /* * CloudConnectionListener APIs */ @Override public void onDisconnected() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onDisconnected)); } @Override public void onConnectionLost() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionLost)); } @Override public void onConnectionEstablished() { this.cloudConnectionListeners.forEach(listener -> this.worker.execute(listener::onConnectionEstablished)); } /* * CloudDeliveryListener APIs */ @Override public void onMessageConfirmed(String messageId) { this.cloudDeliveryListeners .forEach(listener -> this.worker.execute(() -> listener.onMessageConfirmed(messageId))); } private String fillAppTopicPlaceholders(String appTopic, KuraMessage message) { Matcher matcher = TOPIC_PATTERN.matcher(appTopic); StringBuffer buffer = new StringBuffer(); while (matcher.find()) { Map properties = message.getProperties(); if (properties.containsKey(matcher.group(1))) { String replacement = matcher.group(0); Object value = properties.get(matcher.group(1)); if (replacement != null) { matcher.appendReplacement(buffer, value.toString()); } } } matcher.appendTail(buffer); return buffer.toString(); } private String encodeFullTopic(String appTopic) { String accountName = TOPIC_ACCOUNT_TOKEN; String clientId = TOPIC_CLIENT_ID_TOKEN; String topicSeparator = TOPIC_SEPARATOR; StringBuilder sb = new StringBuilder(); Optional topicPrefix = this.options.getTopicPrefix(); if (topicPrefix.isPresent()) { sb.append(topicPrefix.get()).append(topicSeparator); } sb.append(accountName).append(topicSeparator); sb.append(clientId).append(topicSeparator).append(appTopic); return sb.toString(); } } ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisherConstants.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher; public final class EventPublisherConstants { private EventPublisherConstants() { } public static final String TOPIC_ACCOUNT_TOKEN = "#account-name"; public static final String TOPIC_CLIENT_ID_TOKEN = "#client-id"; public static final String TOPIC_SEPARATOR = "/"; public static final String CONTROL = "CONTROL"; public static final String FULL_TOPIC = "FULL_TOPIC"; public static final String PRIORITY = "PRIORITY"; public static final String QOS = "QOS"; public static final String RETAIN = "RETAIN"; } ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/EventPublisherOptions.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher; import java.util.Map; import java.util.Optional; import org.eclipse.kura.cloudconnection.CloudConnectionConstants; import org.eclipse.kura.util.configuration.Property; public class EventPublisherOptions { public static final String TOPIC_PREFIX_PROP_NAME = "topic.prefix"; public static final String TOPIC_PROP_NAME = "topic"; public static final String QOS_PROP_NAME = "qos"; public static final String RETAIN_PROP_NAME = "retain"; public static final String PRIORITY_PROP_NAME = "priority"; public static final String DEFAULT_TOPIC = "EVENT_TOPIC"; public static final int DEFAULT_QOS = 0; public static final boolean DEFAULT_RETAIN = false; public static final int DEFAULT_PRIORITY = 7; public static final String DEFAULT_ENDPOINT_PID = "org.eclipse.kura.cloud.CloudService"; private static final Property PROPERTY_CLOUD_SERVICE_PID = new Property<>( CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), DEFAULT_ENDPOINT_PID); private static final Property PROPERTY_TOPIC_PREFIX = new Property<>(TOPIC_PREFIX_PROP_NAME, String.class); private static final Property PROPERTY_TOPIC = new Property<>(TOPIC_PROP_NAME, DEFAULT_TOPIC); private static final Property PROPERTY_QOS = new Property<>(QOS_PROP_NAME, DEFAULT_QOS); private static final Property PROPERTY_RETAIN = new Property<>(RETAIN_PROP_NAME, DEFAULT_RETAIN); private static final Property PROPERTY_PRIORITY = new Property<>(PRIORITY_PROP_NAME, DEFAULT_PRIORITY); private String cloudEndpointPid; private Optional topicPrefix; private String topic; private int qos; private boolean retain; private int priority; public EventPublisherOptions(final Map properties) { this.cloudEndpointPid = PROPERTY_CLOUD_SERVICE_PID.get(properties); this.topicPrefix = PROPERTY_TOPIC_PREFIX.getOptional(properties); this.topic = PROPERTY_TOPIC.get(properties); this.qos = PROPERTY_QOS.get(properties); this.retain = PROPERTY_RETAIN.get(properties); this.priority = PROPERTY_PRIORITY.get(properties); } public String getCloudEndpointPid() { return this.cloudEndpointPid; } public Optional getTopicPrefix() { if (this.topicPrefix.isPresent()) { if (this.topicPrefix.get().length() == 0) { return Optional.empty(); } return Optional.of(removeTopicSeparatorsFromExtremes(this.topicPrefix.get())); } return this.topicPrefix; } public String getTopic() { return removeTopicSeparatorsFromExtremes(this.topic); } public int getQos() { return this.qos; } public boolean isRetain() { return this.retain; } public int getPriority() { return this.priority; } private String removeTopicSeparatorsFromExtremes(String input) { String result = new String(input); if (result.startsWith(EventPublisherConstants.TOPIC_SEPARATOR)) { result = result.substring(1); } if (result.endsWith(EventPublisherConstants.TOPIC_SEPARATOR)) { result = result.substring(0, result.length() - 1); } return result; } } ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointServiceHelper.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher.helper; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.cloudconnection.message.KuraMessage; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CloudEndpointServiceHelper implements CloudEndpointTrackerListener { private static final Logger logger = LoggerFactory.getLogger(CloudEndpointServiceHelper.class); private CloudEndpointServiceTracker cloudEndpointTracker; private BundleContext context; private CloudEndpoint cloudEndpoint; public CloudEndpointServiceHelper(BundleContext context, String endpointPid) { this.context = context; initCloudEndpointTracker(endpointPid); } public void close() { if (this.cloudEndpointTracker != null) { logger.debug("Closing CloudEndpoint tracker..."); this.cloudEndpointTracker.close(); this.cloudEndpointTracker.unregisterCloudStackTrackerListener(this); this.cloudEndpointTracker = null; this.cloudEndpoint = null; logger.debug("Closing CloudEndpoint tracker... Done."); } } public String publish(KuraMessage message) throws KuraException { if (this.cloudEndpoint == null) { throw new KuraException(KuraErrorCode.PROCESS_EXECUTION_ERROR, "CloudEndpoint not available"); } return this.cloudEndpoint.publish(message); } private void initCloudEndpointTracker(String endpointPid) { try { this.cloudEndpointTracker = new CloudEndpointServiceTracker(this.context, endpointPid); this.cloudEndpointTracker.registerCloudStackTrackerListener(this); this.cloudEndpointTracker.open(); } catch (InvalidSyntaxException e) { logger.error("Service tracker filter setup exception.", e); } } @Override public void onCloudEndpointAdded(CloudEndpoint cloudEndpoint) { this.cloudEndpoint = cloudEndpoint; } @Override public void onCloudEndpointRemoved(CloudEndpoint cloudEndpoint) { this.cloudEndpoint = null; } } ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointServiceTracker.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher.helper; import java.util.HashSet; import java.util.Set; import org.eclipse.kura.cloudconnection.CloudEndpoint; import org.eclipse.kura.configuration.ConfigurationService; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTracker; public class CloudEndpointServiceTracker extends ServiceTracker { private Set listeners = new HashSet<>(); public CloudEndpointServiceTracker(BundleContext context, String endpointPid) throws InvalidSyntaxException { super(context, context.createFilter(String.format("(&(%s=%s)(%s=%s))", Constants.OBJECTCLASS, CloudEndpoint.class.getName(), ConfigurationService.KURA_SERVICE_PID, endpointPid)), null); } public void registerCloudStackTrackerListener(CloudEndpointTrackerListener listener) { this.listeners.add(listener); } public void unregisterCloudStackTrackerListener(CloudEndpointTrackerListener listener) { this.listeners.remove(listener); } @Override public CloudEndpoint addingService(ServiceReference reference) { CloudEndpoint endpoint = super.addingService(reference); for (CloudEndpointTrackerListener listener : this.listeners) { listener.onCloudEndpointAdded(endpoint); } return endpoint; } @Override public void removedService(ServiceReference reference, CloudEndpoint service) { super.removedService(reference, service); for (CloudEndpointTrackerListener listener : this.listeners) { listener.onCloudEndpointRemoved(service); } } } ================================================ FILE: kura/org.eclipse.kura.event.publisher/src/main/java/org/eclipse/kura/event/publisher/helper/CloudEndpointTrackerListener.java ================================================ /******************************************************************************* * Copyright (c) 2022 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.event.publisher.helper; import org.eclipse.kura.cloudconnection.CloudEndpoint; public interface CloudEndpointTrackerListener { public void onCloudEndpointAdded(CloudEndpoint cloudEndpoint); public void onCloudEndpointRemoved(CloudEndpoint cloudEndpoint); } ================================================ FILE: kura/org.eclipse.kura.http.server.manager/META-INF/MANIFEST.MF ================================================ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: org.eclipse.kura.http.server.manager Bundle-SymbolicName: org.eclipse.kura.http.server.manager Bundle-Version: 2.0.0.qualifier Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=21))" Service-Component: OSGI-INF/*.xml Import-Package: jakarta.servlet;version="5.0.0", jakarta.servlet.http;version="5.0.0", org.eclipse.jetty.ee10.servlet;version="12.0.14", org.eclipse.jetty.http;version="12.0.14", org.eclipse.jetty.server;version="12.0.14", org.eclipse.jetty.server.handler;version="12.0.14", org.eclipse.jetty.server.handler.gzip;version="12.0.14", org.eclipse.jetty.session;version="12.0.14", org.eclipse.jetty.util.component;version="12.0.14", org.eclipse.jetty.util.compression;version="12.0.14", org.eclipse.jetty.util.ssl;version="12.0.14", org.eclipse.jetty.util.thread;version="12.0.14", org.eclipse.kura;version="[1.5,2.0)", org.eclipse.kura.configuration;version="1.2.0", org.eclipse.kura.crypto;version="[1.2,2.0)", org.eclipse.kura.security.keystore;version="[1.0,2.0)", org.eclipse.kura.system;version="[1.6,2.0)", org.eclipse.kura.util.configuration;version="[1.0,2.0)", org.osgi.framework;version="1.8.0", org.osgi.service.component;version="1.3.0", org.osgi.service.event;version="1.4.0", org.slf4j;version="1.7.21" Require-Bundle: org.apache.felix.http.bridge;bundle-version="5.1.8" ================================================ FILE: kura/org.eclipse.kura.http.server.manager/OSGI-INF/httpService.xml ================================================ org/eclipse/kura/security/keystore/KeystoreChangedEvent/KEYSTORE_CHANGED ================================================ FILE: kura/org.eclipse.kura.http.server.manager/OSGI-INF/metatype/org.eclipse.kura.http.server.manager.HttpService.xml ================================================ ================================================ FILE: kura/org.eclipse.kura.http.server.manager/about.html ================================================ About

About This Content

November 30, 2017

License

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the Eclipse Public License Version 2.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-2.0. For purposes of the EPL, "Program" will mean the Content.

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

================================================ FILE: kura/org.eclipse.kura.http.server.manager/build.properties ================================================ # # Copyright (c) 2019, 2025 Eurotech and/or its affiliates and others # # This program and the accompanying materials are made # available under the terms of the Eclipse Public License 2.0 # which is available at https://www.eclipse.org/legal/epl-2.0/ # # SPDX-License-Identifier: EPL-2.0 # # Contributors: # Eurotech # source.. = src/main/java/ output.. = target/classes/ bin.includes = META-INF/,\ .,\ OSGI-INF/,\ about.html ================================================ FILE: kura/org.eclipse.kura.http.server.manager/pom.xml ================================================ 4.0.0 org.eclipse.kura kura 6.0.0-SNAPSHOT org.eclipse.kura.http.server.manager eclipse-plugin 2.0.0-SNAPSHOT ${project.basedir}/.. ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml ================================================ FILE: kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/BaseSslContextFactory.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.http.server.manager; import java.security.KeyStore; import javax.net.ssl.KeyManager; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.kura.security.keystore.KeystoreService; public class BaseSslContextFactory extends SslContextFactory.Server { protected final KeystoreService keystoreService; public BaseSslContextFactory(final KeystoreService keystoreService) { this.keystoreService = keystoreService; } @Override protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception { return this.keystoreService.getKeyManagers(getKeyManagerFactoryAlgorithm()).toArray(new KeyManager[0]); } } ================================================ FILE: kura/org.eclipse.kura.http.server.manager/src/main/java/org/eclipse/kura/http/server/manager/ClientAuthSslContextFactoryImpl.java ================================================ /******************************************************************************* * Copyright (c) 2025 Eurotech and/or its affiliates and others * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.http.server.manager; import java.security.KeyStore; import java.security.cert.CertPathValidator; import java.security.cert.CertStore; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXRevocationChecker; import java.security.cert.PKIXRevocationChecker.Option; import java.security.cert.X509CertSelector; import java.util.Collection; import java.util.Set; import org.eclipse.kura.security.keystore.KeystoreService; public final class ClientAuthSslContextFactoryImpl extends BaseSslContextFactory { private boolean isRevocationEnabled; private Set