diff --git a/kura/distrib/config/kura.build.properties b/kura/distrib/config/kura.build.properties index 45452dc301f..32b817725f8 100644 --- a/kura/distrib/config/kura.build.properties +++ b/kura/distrib/config/kura.build.properties @@ -111,6 +111,7 @@ org.eclipse.kura.useradmin.store.version=1.4.0 org.eclipse.kura.network.threat.manager.version=1.4.0 org.eclipse.kura.core.tamper.detection.version=1.4.0 org.eclipse.kura.log.filesystem.provider.version=1.3.0 +org.eclipse.kura.rest.cloudconnection.provider.version=1.0.0 org.eclipse.kura.rest.configuration.provider.version=1.3.0 org.eclipse.kura.rest.inventory.provider.version=1.0.0 org.eclipse.kura.rest.command.provider.version=1.0.0 diff --git a/kura/distrib/pom.xml b/kura/distrib/pom.xml index 224167dced7..3db8846cd6c 100644 --- a/kura/distrib/pom.xml +++ b/kura/distrib/pom.xml @@ -593,6 +593,11 @@ org.eclipse.kura.log.filesystem.provider ${org.eclipse.kura.log.filesystem.provider.version} + + org.eclipse.kura + org.eclipse.kura.rest.cloudconnection.provider + ${org.eclipse.kura.rest.cloudconnection.provider.version} + org.eclipse.kura org.eclipse.kura.rest.configuration.provider @@ -827,6 +832,7 @@ + @@ -2544,6 +2550,7 @@ + diff --git a/kura/distrib/src/main/ant/build_equinox_distrib.xml b/kura/distrib/src/main/ant/build_equinox_distrib.xml index 67d4d3bd205..d9f8f3d9efb 100644 --- a/kura/distrib/src/main/ant/build_equinox_distrib.xml +++ b/kura/distrib/src/main/ant/build_equinox_distrib.xml @@ -1309,6 +1309,8 @@ fi]]> file="${project.build.directory}/${build.output.name}/config.ini"> + + + @@ -1428,9 +1436,6 @@ fi]]> - diff --git a/kura/distrib/src/main/resources/common/Kura_Emulator.launch b/kura/distrib/src/main/resources/common/Kura_Emulator.launch index b8a5ab73635..004ae8ab969 100644 --- a/kura/distrib/src/main/resources/common/Kura_Emulator.launch +++ b/kura/distrib/src/main/resources/common/Kura_Emulator.launch @@ -149,6 +149,7 @@ + diff --git a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-generic-device b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-generic-device index 9f8d49d9a3c..1c84c2cac5f 100644 --- a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-generic-device +++ b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-generic-device @@ -463,7 +463,7 @@ [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.appadmin","credentials":{"kura.password":"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.netadmin","credentials":{"kura.password":"3PgDKAMCxgRWBHiT1dEBS97bPqt7xckgdwrADJiDoWg="},"properties":{"kura.need.password.change":"true"}}] - [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.system"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] + [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.system"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] diff --git a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-intelup2 b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-intelup2 index c0b291bd0e6..9418f345e97 100644 --- a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-intelup2 +++ b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-intelup2 @@ -456,7 +456,7 @@ [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.appadmin","credentials":{"kura.password":"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.netadmin","credentials":{"kura.password":"3PgDKAMCxgRWBHiT1dEBS97bPqt7xckgdwrADJiDoWg="},"properties":{"kura.need.password.change":"true"}}] - [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] + [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] diff --git a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-jetson-nano b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-jetson-nano index 51284f8242e..cc69f8a379e 100644 --- a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-jetson-nano +++ b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-jetson-nano @@ -382,7 +382,7 @@ [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.appadmin","credentials":{"kura.password":"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.netadmin","credentials":{"kura.password":"3PgDKAMCxgRWBHiT1dEBS97bPqt7xckgdwrADJiDoWg="},"properties":{"kura.need.password.change":"true"}}] - [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] + [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.identity"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] diff --git a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-raspberry b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-raspberry index 6ea7e8cc1ea..f12cf845b36 100644 --- a/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-raspberry +++ b/kura/distrib/src/main/resources/common/snapshots/snapshot_0.xml-raspberry @@ -463,7 +463,7 @@ [{"name":"kura.user.admin","credentials":{"kura.password":"jGl25bVBBBW96Qi9Te4V37Fnqchz/Eu4qB9vKrRIqRg="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.appadmin","credentials":{"kura.password":"3hPckF8Zc+IF3pVineBvck3zJERUl8itosySULE1hpM="},"properties":{"kura.need.password.change":"true"}},{"name":"kura.user.netadmin","credentials":{"kura.password":"3PgDKAMCxgRWBHiT1dEBS97bPqt7xckgdwrADJiDoWg="},"properties":{"kura.need.password.change":"true"}}] - [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] + [{"name":"kura.permission.kura.admin","basicMembers":["kura.user.admin"]},{"name":"kura.permission.kura.cloud.connection.admin","basicMembers":["kura.user.appadmin","kura.user.netadmin"]},{"name":"kura.permission.kura.device","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.maintenance"},{"name":"kura.permission.kura.network.admin","basicMembers":["kura.user.netadmin"]},{"name":"kura.permission.kura.packages.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.kura.wires.admin","basicMembers":["kura.user.appadmin"]},{"name":"kura.permission.rest.assets"},{"name":"kura.permission.rest.cloudconnection"},{"name":"kura.permission.rest.command"},{"name":"kura.permission.rest.configuration"},{"name":"kura.permission.rest.inventory"},{"name":"kura.permission.rest.keystores"},{"name":"kura.permission.rest.network.status"},{"name":"kura.permission.rest.position"},{"name":"kura.permission.rest.tamper.detection"},{"name":"kura.permission.rest.wires.admin"}] diff --git a/kura/distrib/src/main/resources/docker-x86_64-nn/snapshot_0.xml b/kura/distrib/src/main/resources/docker-x86_64-nn/snapshot_0.xml index 2c495684955..0f80a539a02 100644 --- a/kura/distrib/src/main/resources/docker-x86_64-nn/snapshot_0.xml +++ b/kura/distrib/src/main/resources/docker-x86_64-nn/snapshot_0.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/about.html b/kura/org.eclipse.kura.rest.cloudconnection.provider/about.html new file mode 100644 index 00000000000..ec5809fefb9 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/about.html @@ -0,0 +1,36 @@ + + + + + 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. +

+ + + \ No newline at end of file diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/about_files/epl-v20.html b/kura/org.eclipse.kura.rest.cloudconnection.provider/about_files/epl-v20.html new file mode 100644 index 00000000000..cc699dea65b --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/about_files/epl-v20.html @@ -0,0 +1,301 @@ + + + + + + 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.

+
+ + \ No newline at end of file diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/build.properties b/kura/org.eclipse.kura.rest.cloudconnection.provider/build.properties new file mode 100644 index 00000000000..61baba2a407 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/build.properties @@ -0,0 +1,19 @@ +# +# 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 +# +output.. = target/classes +bin.includes = .,\ + META-INF/,\ + OSGI-INF/,\ + about.html,\ + about_files/ +source.. = src/main/java/ diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/pom.xml b/kura/org.eclipse.kura.rest.cloudconnection.provider/pom.xml new file mode 100644 index 00000000000..59fe5435f9c --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/pom.xml @@ -0,0 +1,36 @@ + + + + 4.0.0 + + + org.eclipse.kura + kura + 5.4.0 + + + + ${project.basedir}/.. + + ${project.basedir}/../test/*/target/site/jacoco-aggregate/jacoco.xml + + + org.eclipse.kura.rest.cloudconnection.provider + eclipse-plugin + 1.0.0 + + diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionManagerBridge.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionManagerBridge.java new file mode 100644 index 00000000000..5daec5c1c13 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionManagerBridge.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider; + +import static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID; + +import java.util.Collection; +import java.util.concurrent.atomic.AtomicReference; + +import org.eclipse.kura.KuraConnectException; +import org.eclipse.kura.KuraDisconnectException; +import org.eclipse.kura.KuraErrorCode; +import org.eclipse.kura.KuraException; +import org.eclipse.kura.KuraRuntimeException; +import org.eclipse.kura.cloud.CloudService; +import org.eclipse.kura.cloudconnection.CloudConnectionManager; +import org.eclipse.kura.data.DataService; +import org.eclipse.kura.util.service.ServiceUtil; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.osgi.service.component.ComponentConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("deprecation") +public class CloudConnectionManagerBridge { + + private static final String CONNECTION_ERROR_MESSAGE = "Error connecting. Please review your configuration."; + + private static final Logger logger = LoggerFactory.getLogger(CloudConnectionManagerBridge.class); + + private static final String DATA_SERVICE_REFERENCE_NAME = "DataService"; + + private final BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + + public void connectCloudEndpoint(String connectionId) throws KuraException { + + boolean ran = false; + + ran = runOnDataService(connectionId, dataService -> { + int counter = 10; + + dataService.connect(); + while (!dataService.isConnected() && counter > 0) { + Thread.sleep(1000); + counter--; + } + + }); + + ran = ran || runOnCloudConnectionManager(connectionId, cloudConnectionManager -> { + try { + cloudConnectionManager.connect(); + } catch (KuraConnectException e) { + throw new KuraRuntimeException(KuraErrorCode.CONNECTION_FAILED, e, CONNECTION_ERROR_MESSAGE); + } + }); + + if (!ran) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + } + + public void disconnectCloudEndpoint(String connectionId) throws KuraException { + + boolean ran = false; + + ran = runOnDataService(connectionId, dataService -> dataService.disconnect(10)); + + ran = ran || runOnCloudConnectionManager(connectionId, CloudConnectionManager::disconnect); + + if (!ran) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + + } + + public boolean isConnectedCloudEndpoint(String connectionId) throws KuraException { + + boolean ran = false; + + AtomicReference connectionStatusHolder = new AtomicReference<>(false); + + ran = runOnDataService(connectionId, dataService -> connectionStatusHolder.set(dataService.isConnected())); + + ran = ran || runOnCloudConnectionManager(connectionId, + cloudConnectionManager -> connectionStatusHolder.set(cloudConnectionManager.isConnected())); + + if (!ran) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + + return connectionStatusHolder.get(); + + } + + private boolean runOnDataService(String connectionId, InterruptableConsumer dataServiceConsumer) + throws KuraException { + Collection> cloudServiceReferences = ServiceUtil + .getServiceReferencesAsCollection(this.bundleContext, CloudService.class, null); + + for (ServiceReference cloudServiceReference : cloudServiceReferences) { + String cloudServicePid = (String) cloudServiceReference.getProperty(KURA_SERVICE_PID); + if (cloudServicePid.endsWith(connectionId)) { + String dataServiceRef = (String) cloudServiceReference + .getProperty(DATA_SERVICE_REFERENCE_NAME + ComponentConstants.REFERENCE_TARGET_SUFFIX); + Collection> dataServiceReferences = ServiceUtil + .getServiceReferencesAsCollection(this.bundleContext, DataService.class, dataServiceRef); + + for (ServiceReference dataServiceReference : dataServiceReferences) { + DataService dataService = ServiceUtil.getService(this.bundleContext, dataServiceReference); + if (dataService != null) { + + invokeAndHandleExceptions(dataServiceConsumer, dataService); + return true; + } + ServiceUtil.ungetService(this.bundleContext, dataServiceReference); + } + } + ServiceUtil.ungetService(this.bundleContext, cloudServiceReference); + } + + return false; + } + + private boolean runOnCloudConnectionManager(String connectionId, + InterruptableConsumer cloudConnectionManagerConsumer) throws KuraException { + Collection> cloudConnectionManagerReferences = ServiceUtil + .getServiceReferencesAsCollection(this.bundleContext, CloudConnectionManager.class, null); + + for (ServiceReference cloudConnectionManagerReference : cloudConnectionManagerReferences) { + String cloudConnectionManagerPid = (String) cloudConnectionManagerReference.getProperty(KURA_SERVICE_PID); + if (cloudConnectionManagerPid.endsWith(connectionId)) { + CloudConnectionManager cloudConnectionManager = ServiceUtil.getService(this.bundleContext, + cloudConnectionManagerReference); + + invokeAndHandleExceptions(cloudConnectionManagerConsumer, cloudConnectionManager); + + return true; + } + ServiceUtil.ungetService(this.bundleContext, cloudConnectionManagerReference); + } + + return false; + } + + private void invokeAndHandleExceptions(InterruptableConsumer consumer, T service) throws KuraException { + try { + consumer.accept(service); + } catch (KuraConnectException e) { + throw new KuraException(KuraErrorCode.CONNECTION_FAILED, e, CONNECTION_ERROR_MESSAGE); + } catch (IllegalStateException e) { + throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e, "Illegal client state"); + } catch (InterruptedException e) { + logger.warn("Interrupt Exception"); + Thread.currentThread().interrupt(); + } + } + + public interface InterruptableConsumer { + + void accept(T t) + throws InterruptedException, KuraConnectException, KuraDisconnectException, IllegalStateException; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionRestService.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionRestService.java new file mode 100644 index 00000000000..91c7144a16e --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionRestService.java @@ -0,0 +1,288 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.eclipse.kura.cloudconnection.request.RequestHandler; +import org.eclipse.kura.cloudconnection.request.RequestHandlerRegistry; +import org.eclipse.kura.configuration.ComponentConfiguration; +import org.eclipse.kura.configuration.ConfigurationService; +import org.eclipse.kura.crypto.CryptoService; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentFactories; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentInstances; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryPidAndCloudEndpointPid; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointPidRequest; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.ConnectedStatus; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PidAndFactoryPidAndCloudEndpointPid; +import org.eclipse.kura.request.handler.jaxrs.DefaultExceptionHandler; +import org.eclipse.kura.request.handler.jaxrs.JaxRsRequestHandlerProxy; +import org.eclipse.kura.rest.configuration.api.ComponentConfigurationList; +import org.eclipse.kura.rest.configuration.api.DTOUtil; +import org.eclipse.kura.rest.configuration.api.PidAndFactoryPid; +import org.eclipse.kura.rest.configuration.api.PidSet; +import org.eclipse.kura.rest.configuration.api.UpdateComponentConfigurationRequest; +import org.osgi.service.useradmin.Role; +import org.osgi.service.useradmin.UserAdmin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("cloudconnection/v1") +public class CloudConnectionRestService { + + private static final Logger logger = LoggerFactory.getLogger(CloudConnectionRestService.class); + + private static final String MQTT_APP_ID = "CLD-V1"; + private static final String REST_ROLE_NAME = "cloudconnection"; + private static final String KURA_PERMISSION_REST_ROLE = "kura.permission.rest." + REST_ROLE_NAME; + + private final RequestHandler requestHandler = new JaxRsRequestHandlerProxy(this); + + private CloudConnectionService cloudConnectionService; + private CloudConnectionManagerBridge cloudConnectionManagerBridge; + private ConfigurationService configurationService; + private CryptoService cryptoService; + + public void bindUserAdmin(UserAdmin userAdmin) { + userAdmin.createRole(KURA_PERMISSION_REST_ROLE, Role.GROUP); + } + + public void bindCryptoService(CryptoService cryptoService) { + this.cryptoService = cryptoService; + } + + public void bindRequestHandlerRegistry(RequestHandlerRegistry registry) { + try { + registry.registerRequestHandler(MQTT_APP_ID, this.requestHandler); + } catch (final Exception e) { + logger.warn("Failed to register {} request handler", MQTT_APP_ID, e); + } + } + + public void bindConfigurationService(ConfigurationService configurationService) { + this.configurationService = configurationService; + } + + public void unbindRequestHandlerRegistry(RequestHandlerRegistry registry) { + try { + registry.unregister(MQTT_APP_ID); + } catch (final Exception e) { + logger.warn("Failed to unregister {} request handler", MQTT_APP_ID, e); + } + } + + public void activate() { + this.cloudConnectionService = new CloudConnectionService(this.configurationService); + this.cloudConnectionManagerBridge = new CloudConnectionManagerBridge(); + } + + @GET + @RolesAllowed(REST_ROLE_NAME) + @Path("/instances") + @Produces(MediaType.APPLICATION_JSON) + public CloudComponentInstances findCloudComponentInstances() { + try { + return new CloudComponentInstances(this.cloudConnectionService.findCloudEndpointInstances(), + this.cloudConnectionService.findPubsubInstances()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint/stackComponentPids") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public PidSet getStackComponentsPids( + final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) { + try { + Set pidSet = this.cloudConnectionService.getStackComponentsPids( + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(), + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid()); + + return new PidSet(pidSet); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint") + @Consumes(MediaType.APPLICATION_JSON) + public Response createCloudEndpoint( + final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) { + try { + this.cloudConnectionService.createCloudEndpointFromFactory( + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(), + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @DELETE + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint") + @Consumes(MediaType.APPLICATION_JSON) + public Response deleteCloudEndpoint( + final CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid) { + try { + this.cloudConnectionService.deleteCloudEndpointFromFactory( + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudConnectionFactoryPid(), + cloudConnectionFactoryPidAndCloudEndpointPid.getCloudEndpointPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @GET + @RolesAllowed(REST_ROLE_NAME) + @Path("/factories") + @Produces(MediaType.APPLICATION_JSON) + public CloudComponentFactories getCloudComponentFactories() { + try { + return this.cloudConnectionService.getCloudComponentFactories(); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/pubSub") + @Consumes(MediaType.APPLICATION_JSON) + public Response createPubSubInstance( + final PidAndFactoryPidAndCloudEndpointPid pidAndFactoryPidAndCloudEndpointPid) { + try { + this.cloudConnectionService.createPubSubInstance(pidAndFactoryPidAndCloudEndpointPid.getPid(), + pidAndFactoryPidAndCloudEndpointPid.getFactoryPid(), + pidAndFactoryPidAndCloudEndpointPid.getCloudEndpointPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @DELETE + @RolesAllowed(REST_ROLE_NAME) + @Path("/pubSub") + @Consumes(MediaType.APPLICATION_JSON) + public Response deletePubSubInstance(final PidAndFactoryPid pidAndFactoryPid) { + try { + this.cloudConnectionService.deletePubSubInstance(pidAndFactoryPid.getPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/configurations") + @Consumes(MediaType.APPLICATION_JSON) + public ComponentConfigurationList getConfigurations(final PidSet pidSet) { + try { + List result = this.cloudConnectionService.getPubSubConfiguration(pidSet.getPids()); + + result.addAll(this.cloudConnectionService.getStackConfigurationsByPid(pidSet.getPids())); + + return new ComponentConfigurationList( + result.stream().map(c -> DTOUtil.toComponentConfigurationDTO(c, this.cryptoService, false) + .replacePasswordsWithPlaceholder()).collect(Collectors.toList())); + + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + } + + @PUT + @RolesAllowed(REST_ROLE_NAME) + @Path("/configurations") + @Consumes(MediaType.APPLICATION_JSON) + public Response updateStackComponentConfigurations( + UpdateComponentConfigurationRequest updateComponentConfigurationRequest) { + try { + this.cloudConnectionService.updateStackComponentConfiguration( + updateComponentConfigurationRequest.getComponentConfigurations(), + updateComponentConfigurationRequest.isTakeSnapshot()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint/connect") + @Consumes(MediaType.APPLICATION_JSON) + public Response connectCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) { + try { + this.cloudConnectionManagerBridge.connectCloudEndpoint(cloudEndpointPid.getCloudEndpointPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint/disconnect") + @Consumes(MediaType.APPLICATION_JSON) + public Response disconnectCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) { + try { + this.cloudConnectionManagerBridge.disconnectCloudEndpoint(cloudEndpointPid.getCloudEndpointPid()); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + + return Response.ok().build(); + } + + @POST + @RolesAllowed(REST_ROLE_NAME) + @Path("/cloudEndpoint/isConnected") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public ConnectedStatus isConnectedCloudEndpoint(CloudEndpointPidRequest cloudEndpointPid) { + try { + return new ConnectedStatus( + this.cloudConnectionManagerBridge.isConnectedCloudEndpoint(cloudEndpointPid.getCloudEndpointPid())); + } catch (Exception e) { + throw DefaultExceptionHandler.toWebApplicationException(e); + } + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionService.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionService.java new file mode 100644 index 00000000000..6c4d7511c05 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/CloudConnectionService.java @@ -0,0 +1,509 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider; + +import static java.lang.String.format; +import static org.eclipse.kura.configuration.ConfigurationService.KURA_SERVICE_PID; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +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.cloud.CloudService; +import org.eclipse.kura.cloud.factory.CloudServiceFactory; +import org.eclipse.kura.cloudconnection.CloudConnectionConstants; +import org.eclipse.kura.cloudconnection.CloudConnectionManager; +import org.eclipse.kura.cloudconnection.CloudEndpoint; +import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; +import org.eclipse.kura.cloudconnection.publisher.CloudPublisher; +import org.eclipse.kura.cloudconnection.subscriber.CloudSubscriber; +import org.eclipse.kura.configuration.ComponentConfiguration; +import org.eclipse.kura.configuration.ConfigurationService; +import org.eclipse.kura.core.configuration.ComponentConfigurationImpl; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudComponentFactories; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryInfo; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionState; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointInstance; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointType; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudPubSubType; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PubSubFactoryInfo; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PubSubInstance; +import org.eclipse.kura.rest.configuration.api.ComponentConfigurationDTO; +import org.eclipse.kura.rest.configuration.api.DTOUtil; +import org.eclipse.kura.util.service.ServiceUtil; +import org.eclipse.kura.util.service.ServiceUtil.ServiceConsumer; +import org.eclipse.kura.util.service.ServiceUtil.ServiceReferenceConsumer; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.component.runtime.ServiceComponentRuntime; +import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@SuppressWarnings("deprecation") +public class CloudConnectionService { + + private static final Logger logger = LoggerFactory.getLogger(CloudConnectionService.class); + + private static final String CLOUD_CONNECTION_FACTORY_FILTER = "(" + "|" + + "(objectClass=org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory)" + + "(objectClass=org.eclipse.kura.cloud.factory.CloudServiceFactory)" + ")"; + + private static final String KURA_UI_CSF_PID_DEFAULT = "kura.ui.csf.pid.default"; + private static final String KURA_UI_CSF_PID_REGEX = "kura.ui.csf.pid.regex"; + + private static final String CLOUD_PUBLISHER = CloudPublisher.class.getName(); + private static final String CLOUD_SUBSCRIBER = CloudSubscriber.class.getName(); + + private final BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + + private final ConfigurationService configurationService; + + public CloudConnectionService(ConfigurationService configurationService) { + this.configurationService = configurationService; + } + + public List findCloudEndpointInstances() throws KuraException { + + final List result = new ArrayList<>(); + + withAllCloudConnectionFactories(service -> { + + final String factoryPid = service.getFactoryPid(); + if (factoryPid == null) { + return; + } + + for (final String pid : service.getManagedCloudConnectionPids()) { + if (pid == null) { + continue; + } + + final CloudEndpointInstance cloudConnectionEntry = new CloudEndpointInstance(factoryPid, pid); + + fillState(cloudConnectionEntry); + + result.add(cloudConnectionEntry); + } + + }); + + return result; + } + + public List findPubsubInstances() throws KuraException { + final List result = new ArrayList<>(); + + result.addAll(getPubSubInstances(CloudPubSubType.PUBLISHER)); + result.addAll(getPubSubInstances(CloudPubSubType.SUBSCRIBER)); + + return result; + } + + public Set getStackComponentsPids(final String factoryPid, final String cloudEndpointPid) + throws KuraException { + + final Set result = new HashSet<>(); + + withAllCloudConnectionFactories(factory -> { + if (factoryPid.equals(factory.getFactoryPid())) { + if (!factory.getManagedCloudConnectionPids().contains(cloudEndpointPid)) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + result.addAll(getStackComponentPids(factory, cloudEndpointPid)); + } + }); + + return result; + } + + private List getStackComponentPids(CloudConnectionFactory factory, String pid) { + + List result = new ArrayList<>(); + + try { + result = factory.getStackComponentsPids(pid); + } catch (Exception e) { + // nothing to do, just return an empty list + } + + return result; + } + + public Set getStackConfigurationsByPid(final Set pids) throws KuraException { + + List result = new ArrayList<>(); + + Set resultSet = new HashSet<>(); + + withAllCloudConnectionFactories(factory -> { + + Set managedCloudConnectionPids = factory.getManagedCloudConnectionPids(); + + for (String cloudConnectionPid : managedCloudConnectionPids) { + List stackComponentsPids = getStackComponentPids(factory, cloudConnectionPid); + + pids.stream().filter(stackComponentsPids::contains).forEach(result::add); + } + + }); + + for (String stackConfigurationPid : result) { + ComponentConfiguration componetConfiguration = this.configurationService + .getComponentConfiguration(stackConfigurationPid); + if (componetConfiguration != null) { + resultSet.add(componetConfiguration); + } + } + + return resultSet; + } + + public void createCloudEndpointFromFactory(String factoryPid, String cloudServicePid) throws KuraException { + if (factoryPid == null || factoryPid.trim().isEmpty() || cloudServicePid == null + || cloudServicePid.trim().isEmpty()) { + throw new KuraException(KuraErrorCode.BAD_REQUEST); + } + + AtomicReference found = new AtomicReference<>(false); + + withAllCloudConnectionFactories(service -> { + if (service.getFactoryPid().equals(factoryPid)) { + found.set(true); + service.createConfiguration(cloudServicePid); + } + }); + + if (Boolean.FALSE.equals(found.get())) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + } + + public void deleteCloudEndpointFromFactory(String factoryPid, String cloudEndpointPid) throws KuraException { + if (factoryPid == null || factoryPid.trim().isEmpty() || cloudEndpointPid == null + || cloudEndpointPid.trim().isEmpty()) { + throw new KuraException(KuraErrorCode.BAD_REQUEST); + } + + AtomicReference found = new AtomicReference<>(false); + + withAllCloudConnectionFactories(factory -> { + if (factory.getFactoryPid().equals(factoryPid) + && factory.getManagedCloudConnectionPids().contains(cloudEndpointPid)) { + + factory.deleteConfiguration(cloudEndpointPid); + found.set(true); + } + }); + + if (Boolean.FALSE.equals(found.get())) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + } + + public CloudComponentFactories getCloudComponentFactories() throws KuraException { + final List cloudConnectionFactoryPids = new ArrayList<>(); + + withAllCloudConnectionFactoryRefs((ref, ctx) -> { + + try { + final CloudConnectionFactory service = wrap(ctx.getService(ref)); + String defaultPid = (String) ref.getProperty(KURA_UI_CSF_PID_DEFAULT); + String pidRegex = (String) ref.getProperty(KURA_UI_CSF_PID_REGEX); + + CloudConnectionFactoryInfo cloudConnectionFactoryInfoDTO = new CloudConnectionFactoryInfo( + service.getFactoryPid(), defaultPid, pidRegex); + + cloudConnectionFactoryPids.add(cloudConnectionFactoryInfoDTO); + } finally { + ctx.ungetService(ref); + } + + }); + + final List pubSubFactories = getPubSubFactories(); + + return new CloudComponentFactories(cloudConnectionFactoryPids, pubSubFactories); + } + + public void createPubSubInstance(final String pid, final String factoryPid, final String cloudEndpointPid) + throws KuraException { + + if (pid == null || pid.trim().isEmpty() || // + factoryPid == null || factoryPid.trim().isEmpty() // + || cloudEndpointPid == null || cloudEndpointPid.trim().isEmpty()) { + throw new KuraException(KuraErrorCode.BAD_REQUEST); + } + + requireIsPubSubFactory(factoryPid); + + ServiceUtil.applyToServiceOptionally(this.bundleContext, ConfigurationService.class, cs -> { + cs.createFactoryConfiguration(factoryPid, pid, Collections.singletonMap( + CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), cloudEndpointPid), true); + + return null; + }); + } + + public void deletePubSubInstance(final String pid) throws KuraException { + + requireIsPubSub(pid); + + ServiceUtil.applyToServiceOptionally(this.bundleContext, ConfigurationService.class, cs -> { + cs.deleteFactoryConfiguration(pid, true); + + return null; + }); + } + + public List getPubSubConfiguration(Set pids) throws KuraException { + + List result = new ArrayList<>(); + + for (String pid : pids) { + if (isPubSub(pid)) { + ComponentConfiguration configuration = this.configurationService.getComponentConfiguration(pid); + if (configuration != null) { + result.add(configuration); + } + } + } + + return result; + } + + public void updateStackComponentConfiguration(List componentConfigurations, + boolean takeSnapshot) throws KuraException { + + for (ComponentConfigurationDTO componentConfig : componentConfigurations) { + if (!(isPubSub(componentConfig.getPid()) || isComponentManagedByFactory(componentConfig.getPid()))) { + throw new KuraException(KuraErrorCode.BAD_REQUEST); + } + } + + updateComponentConfigurations(componentConfigurations, takeSnapshot); + + } + + private void updateComponentConfigurations(List componentConfigurations, + boolean takeSnapshot) throws KuraException { + + List configs = componentConfigurations.stream() + .map(cc -> new ComponentConfigurationImpl(cc.getPid(), null, + DTOUtil.dtosToConfigurationProperties(cc.getProperties()))) + .collect(Collectors.toList()); + + this.configurationService.updateConfigurations(configs, takeSnapshot); + } + + private boolean isComponentManagedByFactory(final String pid) { + final AtomicBoolean result = new AtomicBoolean(false); + + try { + withAllCloudConnectionFactories(f -> { + for (final String stackPid : f.getManagedCloudConnectionPids()) { + if (f.getStackComponentsPids(stackPid).contains(pid)) { + result.set(true); + return; + } + } + }); + } catch (final Exception e) { + return false; + } + + return result.get(); + } + + private void requireIsPubSub(final String pid) throws KuraException { + if (!isPubSub(pid)) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + } + + private boolean isPubSub(final String pid) { + return ServiceUtil.providesService(this.bundleContext, pid, CloudPublisher.class) + || ServiceUtil.providesService(this.bundleContext, pid, CloudSubscriber.class); + } + + private List getPubSubFactories() throws KuraException { + + return ServiceUtil.applyToServiceOptionally(this.bundleContext, ServiceComponentRuntime.class, scr -> + + scr.getComponentDescriptionDTOs().stream().map(this::pubSubFactoryToInfo).filter(Objects::nonNull) + .collect(Collectors.toList())); + } + + private void requireIsPubSubFactory(final String factoryPid) throws KuraException { + final boolean isPubSub = ServiceUtil.applyToServiceOptionally(this.bundleContext, ServiceComponentRuntime.class, + scr -> scr.getComponentDescriptionDTOs().stream().anyMatch(c -> { + final Map properties = c.properties; + + if (properties == null) { + return false; + } + + return Objects.equals(factoryPid, properties.get("service.pid")) && pubSubFactoryToInfo(c) != null; + })); + + if (!isPubSub) { + throw new KuraException(KuraErrorCode.NOT_FOUND); + } + } + + private PubSubFactoryInfo pubSubFactoryToInfo(final ComponentDescriptionDTO component) { + + if (Arrays.stream(component.serviceInterfaces) + .noneMatch(intf -> CLOUD_PUBLISHER.equals(intf) || CLOUD_SUBSCRIBER.equals(intf))) { + return null; + } + + final String ccsfFactoryPidPropName = CloudConnectionConstants.CLOUD_CONNECTION_FACTORY_PID_PROP_NAME.value(); + + final Object ccsfFactoryPid = component.properties.get(ccsfFactoryPidPropName); + final Object factoryPid = component.properties.get("service.pid"); + final Object defaultFactoryPid = component.properties.get(KURA_UI_CSF_PID_DEFAULT); + final Object defaultFactoryPidRegex = component.properties.get(KURA_UI_CSF_PID_REGEX); + + if (!(factoryPid instanceof String)) { + logger.warn( + "component {} defines a CloudPublisher or CloudSubscriber but does not specify the service.pid property, ignoring it", + component.name); + return null; + } + + if (!(ccsfFactoryPid instanceof String)) { + logger.warn( + "component {} defines a CloudPublisher or CloudSubscriber but does not specify the {} property, ignoring it", + component.name, ccsfFactoryPidPropName); + return null; + } + + return new PubSubFactoryInfo((String) factoryPid, (String) ccsfFactoryPid, (String) defaultFactoryPid, + (String) defaultFactoryPidRegex); + } + + private void fillState(final CloudEndpointInstance cloudEndpointInstance) throws KuraException { + + cloudEndpointInstance.setState(CloudConnectionState.UNREGISTERED); + + final String filter = format("(%s=%s)", KURA_SERVICE_PID, cloudEndpointInstance.getCloudEndpointPid()); + + ServiceUtil.withAllServices(this.bundleContext, null, filter, service -> { + if (service instanceof CloudConnectionManager) { + cloudEndpointInstance + .setState(((CloudConnectionManager) service).isConnected() ? CloudConnectionState.CONNECTED + : CloudConnectionState.DISCONNECTED); + cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_CONNECTION_MANAGER); + } else if (service instanceof CloudEndpoint) { + cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_ENDPOINT); + } else if (service instanceof CloudService) { + cloudEndpointInstance.setState(((CloudService) service).isConnected() ? CloudConnectionState.CONNECTED + : CloudConnectionState.DISCONNECTED); + cloudEndpointInstance.setConnectionType(CloudEndpointType.CLOUD_CONNECTION_MANAGER); + } + }); + } + + private void withAllCloudConnectionFactoryRefs(final ServiceReferenceConsumer consumer) + throws KuraException { + ServiceUtil.withAllServiceReferences(this.bundleContext, CLOUD_CONNECTION_FACTORY_FILTER, consumer); + } + + private void withAllCloudConnectionFactories(final ServiceConsumer consumer) + throws KuraException { + ServiceUtil.withAllServices(this.bundleContext, CLOUD_CONNECTION_FACTORY_FILTER, + o -> consumer.consume(wrap(o))); + } + + private CloudConnectionFactory wrap(final Object o) { + if (o instanceof CloudConnectionFactory) { + return (CloudConnectionFactory) o; + } else if (o instanceof CloudServiceFactory) { + final CloudServiceFactory f = (CloudServiceFactory) o; + + return new CloudConnectionFactory() { + + @Override + public List getStackComponentsPids(String pid) throws KuraException { + return f.getStackComponentsPids(pid); + } + + @Override + public Set getManagedCloudConnectionPids() throws KuraException { + return f.getManagedCloudServicePids(); + } + + @Override + public String getFactoryPid() { + return f.getFactoryPid(); + } + + @Override + public void deleteConfiguration(String pid) throws KuraException { + f.deleteConfiguration(pid); + } + + @Override + public void createConfiguration(String pid) throws KuraException { + f.createConfiguration(pid); + } + }; + } + return null; + } + + private Set getPubSubInstances(CloudPubSubType type) throws KuraException { + + final Set result = new HashSet<>(); + + Class clazz = (type == CloudPubSubType.PUBLISHER) ? CloudPublisher.class : CloudSubscriber.class; + + try { + this.bundleContext.getServiceReferences(clazz, null).stream().map(ref -> pubSubRefToDTO(ref, type)) + .filter(Objects::nonNull).forEach(result::add); + + return result; + } catch (InvalidSyntaxException e) { + throw new KuraException(KuraErrorCode.INVALID_PARAMETER, "Unexpected error"); + } + } + + private static PubSubInstance pubSubRefToDTO(final ServiceReference ref, final CloudPubSubType type) { + final Object ccsPid = ref.getProperty(CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value()); + final Object factoryPid = ref.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID); + + if (!(ccsPid instanceof String && factoryPid instanceof String)) { + return null; + } + + final String kuraServicePid = (String) ref.getProperty(ConfigurationService.KURA_SERVICE_PID); + + return new PubSubInstance((String) ccsPid, kuraServicePid, (String) factoryPid, type); + + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentFactories.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentFactories.java new file mode 100644 index 00000000000..eafc2a23219 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentFactories.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +import java.util.List; + +public class CloudComponentFactories { + + private final List cloudConnectionFactories; + private final List pubSubFactories; + + public CloudComponentFactories(List cloudConnectionFactories, + List pubSubFactories) { + + this.cloudConnectionFactories = cloudConnectionFactories; + this.pubSubFactories = pubSubFactories; + } + + public List getCloudConnectionFactories() { + return this.cloudConnectionFactories; + } + + public List getPubSubFactories() { + return this.pubSubFactories; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentInstances.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentInstances.java new file mode 100644 index 00000000000..5a2bc5acb1c --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudComponentInstances.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +import java.util.ArrayList; +import java.util.List; + +public class CloudComponentInstances { + + private List cloudEndpointInstances = new ArrayList<>(); + private List pubsubInstances = new ArrayList<>(); + + public CloudComponentInstances(List cloudEndpointInstances, + List pubsubInstances) { + super(); + this.cloudEndpointInstances = cloudEndpointInstances; + this.pubsubInstances = pubsubInstances; + } + + public List getCloudEndpointInstances() { + return this.cloudEndpointInstances; + } + + public List getPubsubInstances() { + return this.pubsubInstances; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryInfo.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryInfo.java new file mode 100644 index 00000000000..8dfdcb631b4 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryInfo.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class CloudConnectionFactoryInfo { + + private final String cloudConnectionFactoryPid; + private final String defaultCloudEndpointPid; + private final String cloudEndpointPidRegex; + + public CloudConnectionFactoryInfo(String cloudConnectionFactoryPid, String defaultCloudEndpointPid, + String cloudEndpointPidRegex) { + + this.cloudConnectionFactoryPid = cloudConnectionFactoryPid; + this.defaultCloudEndpointPid = defaultCloudEndpointPid; + this.cloudEndpointPidRegex = cloudEndpointPidRegex; + } + + public String getCloudConnectionFactoryPid() { + return this.cloudConnectionFactoryPid; + } + + public String getDefaultCloudEndpointPid() { + return this.defaultCloudEndpointPid; + } + + public String getCloudEndpointPidRegex() { + return this.cloudEndpointPidRegex; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryPidAndCloudEndpointPid.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryPidAndCloudEndpointPid.java new file mode 100644 index 00000000000..4b3413f6120 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionFactoryPidAndCloudEndpointPid.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class CloudConnectionFactoryPidAndCloudEndpointPid { + + private final String cloudConnectionFactoryPid; + private final String cloudEndpointPid; + + public CloudConnectionFactoryPidAndCloudEndpointPid(String cloudConnectionFactoryPid, String cloudEndpointPid) { + super(); + this.cloudConnectionFactoryPid = cloudConnectionFactoryPid; + this.cloudEndpointPid = cloudEndpointPid; + } + + public String getCloudConnectionFactoryPid() { + return this.cloudConnectionFactoryPid; + } + + public String getCloudEndpointPid() { + return this.cloudEndpointPid; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionState.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionState.java new file mode 100644 index 00000000000..c161c59a37c --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudConnectionState.java @@ -0,0 +1,19 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public enum CloudConnectionState { + UNREGISTERED, + DISCONNECTED, + CONNECTED; +} \ No newline at end of file diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointInstance.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointInstance.java new file mode 100644 index 00000000000..6dcf6d26b9f --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointInstance.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class CloudEndpointInstance { + + private final String cloudConnectionFactoryPid; + private final String cloudEndpointPid; + private CloudConnectionState state; + private CloudEndpointType cloudEndpointType; + + public CloudEndpointInstance(String cloudConnectionFactoryPid, String cloudEndpointPid) { + super(); + this.cloudConnectionFactoryPid = cloudConnectionFactoryPid; + this.cloudEndpointPid = cloudEndpointPid; + } + + public String getCloudConnectionFactoryPid() { + return this.cloudConnectionFactoryPid; + } + + public String getCloudEndpointPid() { + return this.cloudEndpointPid; + } + + public CloudConnectionState getState() { + return this.state; + } + + public void setState(CloudConnectionState state) { + this.state = state; + } + + public CloudEndpointType getCloudEndpointType() { + return this.cloudEndpointType; + } + + public void setConnectionType(CloudEndpointType connectionType) { + this.cloudEndpointType = connectionType; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointPidRequest.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointPidRequest.java new file mode 100644 index 00000000000..9e805953ad6 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointPidRequest.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class CloudEndpointPidRequest { + + private final String cloudEndpointPid; + + public CloudEndpointPidRequest(String cloudEndpointPid) { + + this.cloudEndpointPid = cloudEndpointPid; + } + + public String getCloudEndpointPid() { + return this.cloudEndpointPid; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointType.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointType.java new file mode 100644 index 00000000000..f90471e2d9c --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudEndpointType.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public enum CloudEndpointType { + CLOUD_ENDPOINT, + CLOUD_CONNECTION_MANAGER; +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudPubSubType.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudPubSubType.java new file mode 100644 index 00000000000..f9438018255 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/CloudPubSubType.java @@ -0,0 +1,18 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public enum CloudPubSubType { + PUBLISHER, + SUBSCRIBER +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/ConnectedStatus.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/ConnectedStatus.java new file mode 100644 index 00000000000..b81a1dbdac6 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/ConnectedStatus.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class ConnectedStatus { + + private final boolean connected; + + public ConnectedStatus(boolean connected) { + this.connected = connected; + } + + public boolean isConnected() { + return this.connected; + } +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PidAndFactoryPidAndCloudEndpointPid.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PidAndFactoryPidAndCloudEndpointPid.java new file mode 100644 index 00000000000..43b00510baf --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PidAndFactoryPidAndCloudEndpointPid.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class PidAndFactoryPidAndCloudEndpointPid { + + private final String pid; + private final String factoryPid; + private final String cloudEndpointPid; + + public PidAndFactoryPidAndCloudEndpointPid(String pid, String factoryPid, String cloudEndpointPid) { + + this.pid = pid; + this.factoryPid = factoryPid; + this.cloudEndpointPid = cloudEndpointPid; + } + + public String getPid() { + return this.pid; + } + + public String getFactoryPid() { + return this.factoryPid; + } + + public String getCloudEndpointPid() { + return this.cloudEndpointPid; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubFactoryInfo.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubFactoryInfo.java new file mode 100644 index 00000000000..cc6e6b67cf5 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubFactoryInfo.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class PubSubFactoryInfo { + + private final String factoryPid; + private final String cloudConnectionFactoryPid; + private final String defaultPid; + private final String defaultPidRegex; + + public PubSubFactoryInfo(String factoryPid, String cloudConnectionFactoryPid, String defaultPid, + String defaultPidRegex) { + + this.factoryPid = factoryPid; + this.cloudConnectionFactoryPid = cloudConnectionFactoryPid; + this.defaultPid = defaultPid; + this.defaultPidRegex = defaultPidRegex; + } + + public String getFactoryPid() { + return this.factoryPid; + } + + public String getCloudConnectionFactoryPid() { + return this.cloudConnectionFactoryPid; + } + + public String getDefaultPid() { + return this.defaultPid; + } + + public String getDefaultPidRegex() { + return this.defaultPidRegex; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubInstance.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubInstance.java new file mode 100644 index 00000000000..c4fa64714e7 --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/dto/PubSubInstance.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.dto; + +public class PubSubInstance { + + private final String cloudEndpointPid; + private final String pid; + private final String factoryPid; + private final CloudPubSubType type; + + public PubSubInstance(String cloudEndpointPid, String pid, String factoryPid, CloudPubSubType type) { + this.cloudEndpointPid = cloudEndpointPid; + this.pid = pid; + this.factoryPid = factoryPid; + this.type = type; + } + + public String getCloudEndpointPid() { + return this.cloudEndpointPid; + } + + public String getPid() { + return this.pid; + } + + public String getFactoryPid() { + return this.factoryPid; + } + + public CloudPubSubType getType() { + return this.type; + } + +} diff --git a/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/util/PidUtils.java b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/util/PidUtils.java new file mode 100644 index 00000000000..3f80968d7ab --- /dev/null +++ b/kura/org.eclipse.kura.rest.cloudconnection.provider/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/util/PidUtils.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.util; + +import java.util.Iterator; + +public class PidUtils { + + private PidUtils() { + + } + + public static String getPidFilter(final Iterator pids) { + if (!pids.hasNext()) { + throw new IllegalArgumentException("pids list must be non empty"); + } + final StringBuilder builder = new StringBuilder(); + builder.append("(|"); + while (pids.hasNext()) { + final String pid = pids.next(); + builder.append("(kura.service.pid="); + builder.append(pid); + builder.append(")"); + } + builder.append(")"); + return builder.toString(); + } + + public static String stripPidPrefix(String pid) { + int start = pid.lastIndexOf('.'); + if (start < 0) { + return pid; + } else { + int begin = start + 1; + if (begin < pid.length()) { + return pid.substring(begin); + } else { + return pid; + } + } + } +} diff --git a/kura/org.eclipse.kura.util/META-INF/MANIFEST.MF b/kura/org.eclipse.kura.util/META-INF/MANIFEST.MF index c42ba3f2be8..d3310d3c876 100644 --- a/kura/org.eclipse.kura.util/META-INF/MANIFEST.MF +++ b/kura/org.eclipse.kura.util/META-INF/MANIFEST.MF @@ -30,7 +30,7 @@ Export-Package: org.eclipse.kura.util.base;version="1.2.0", org.eclipse.kura.util.jdbc;version="1.0.0";x-internal:=true, org.eclipse.kura.util.message.store;version="1.0.0";x-internal:=true, org.eclipse.kura.util.osgi;version="1.1.0", - org.eclipse.kura.util.service;version="1.1.0", + org.eclipse.kura.util.service;version="1.2.0", org.eclipse.kura.util.store.listener;version="1.0.0";x-internal:=true, org.eclipse.kura.util.useradmin;version="1.0.0";x-internal:=true, org.eclipse.kura.util.validation;version="1.0.0";x-internal:=true, diff --git a/kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/service/ServiceUtil.java b/kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/service/ServiceUtil.java index 33280ad6297..bbdb10c1b2c 100644 --- a/kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/service/ServiceUtil.java +++ b/kura/org.eclipse.kura.util/src/main/java/org/eclipse/kura/util/service/ServiceUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others + * Copyright (c) 2016, 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 @@ -27,6 +27,8 @@ import java.util.function.Predicate; import java.util.stream.Collectors; +import org.eclipse.kura.KuraErrorCode; +import org.eclipse.kura.KuraException; import org.eclipse.kura.annotation.Nullable; import org.osgi.framework.BundleContext; import org.osgi.framework.Filter; @@ -76,6 +78,36 @@ public static ServiceReference[] getServiceReferences(final BundleContext } } + public static Collection> getServiceReferencesAsCollection( + final BundleContext bundleContext, Class serviceClass, String filter) throws KuraException { + + try { + final Collection> sr = bundleContext.getServiceReferences(serviceClass, filter); + + if (sr == null) { + throw KuraException.internalError(serviceClass.toString() + " not found."); + } + + return sr; + } catch (InvalidSyntaxException e) { + throw new IllegalArgumentException(e); + } + + } + + public static T getService(final BundleContext bundleContext, ServiceReference serviceReference) + throws KuraException { + T service = null; + + if (serviceReference != null) { + service = bundleContext.getService(serviceReference); + } + if (service == null) { + throw KuraException.internalError("Service not found."); + } + return service; + } + /** * Resets all the provided service reference use counts. If the provided {@link BundleContext} bundle's use count * for the provided service references are already zero, this would not further decrement the counters to @@ -156,6 +188,153 @@ public static T withService(final BundleContext bundleContext, final Functio } } + /** + * Lookup services with a filter and iterate over their instances + * + * @param serviceClass + * the services to look for + * @param consumer + * the consumer which will be called for each service instance + * @throws GwtKuraException + * if any service consumer throws an exception + * @throws InvalidSyntaxException + * if the filter was not {@code null} and had an invalid syntax + */ + public static void withAllServices(final BundleContext bundleContext, final Class serviceClass, + String filter, final ServiceConsumer consumer) throws KuraException { + + withAllServiceReferences(bundleContext, serviceClass, filter, (ref, ctx) -> { + final T service = ctx.getService(ref); + + try { + consumer.consume(service); + } finally { + ctx.ungetService(ref); + } + }); + } + + @SuppressWarnings("unchecked") + public static void withAllServiceReferences(final BundleContext bundleContext, final Class serviceClass, + String filter, final ServiceReferenceConsumer consumer) throws KuraException { + + final ServiceReference[] refs; + try { + refs = bundleContext.getAllServiceReferences(serviceClass != null ? serviceClass.getName() : null, filter); + } catch (InvalidSyntaxException e) { + throw new KuraException(KuraErrorCode.INVALID_PARAMETER, + serviceClass != null ? serviceClass.getName() : ""); + } + + // no result ... do nothing + if (refs == null) { + return; + } + + // iterate over results + for (final ServiceReference ref : refs) { + consumer.consume((ServiceReference) ref, bundleContext); + } + } + + @SuppressWarnings("unchecked") + public static void withAllServices(final BundleContext bundleContext, String filter, + final ServiceConsumer consumer, final Class... classes) throws KuraException { + + if (classes == null || classes.length == 0) { + withAllServices(bundleContext, null, filter, consumer); + } + + for (Class c : classes) { + withAllServices(bundleContext, (Class) c, filter, consumer); + } + } + + @SuppressWarnings("unchecked") + public static void withAllServiceReferences(final BundleContext bundleContext, String filter, + final ServiceReferenceConsumer consumer, final Class... classes) throws KuraException { + + if (classes == null || classes.length == 0) { + withAllServiceReferences(bundleContext, null, filter, consumer); + } + + for (Class c : classes) { + withAllServiceReferences(bundleContext, (Class) c, filter, consumer); + } + } + + public static boolean ungetService(final BundleContext bundleContext, ServiceReference serviceReference) { + + if (serviceReference != null) { + return bundleContext.ungetService(serviceReference); + } + + return false; + } + + public static R applyToServiceOptionally(final BundleContext bundleContext, final Class serviceClass, + final ServiceFunction function) throws KuraException { + + final ServiceReference ref = bundleContext.getServiceReference(serviceClass); + + try { + if (ref == null) { + return function.apply(null); + } + + final T service = bundleContext.getService(ref); + try { + return function.apply(service); + } finally { + bundleContext.ungetService(ref); + } + } catch (Exception e) { + throw KuraException.internalError(e.getMessage()); + } + } + + public static boolean providesService(final BundleContext bundleContext, final String kuraServicePid, + final Class serviceInterface) { + return providesService(bundleContext, kuraServicePid, s -> s.contains(serviceInterface.getName())); + } + + public static boolean providesService(final BundleContext bundleContext, final String kuraServicePid, + final Predicate> filter) { + + final String pidFilter = "(kura.service.pid=" + kuraServicePid + ")"; + + try { + final ServiceReference[] refs = bundleContext.getAllServiceReferences(null, pidFilter); + + if (refs == null) { + return false; + } + + for (final ServiceReference ref : refs) { + final Object rawProvidedInterfaces = ref.getProperty("objectClass"); + + final Set providedInterfaces; + + if (rawProvidedInterfaces instanceof String) { + providedInterfaces = Collections.singleton((String) rawProvidedInterfaces); + } else if (rawProvidedInterfaces instanceof String[]) { + providedInterfaces = Arrays.asList((String[]) rawProvidedInterfaces).stream() + .collect(Collectors.toSet()); + } else { + providedInterfaces = Collections.emptySet(); + } + + if (filter.test(providedInterfaces)) { + return true; + } + } + + return false; + } catch (InvalidSyntaxException e) { + return false; + } + } + public static boolean isFactoryOf(final BundleContext bundleContext, final String factoryPid, final Predicate> filter) { @@ -206,4 +385,20 @@ public static boolean isFactoryOfAnyService(final BundleContext bundleContext, f return false; }); } + + public interface ServiceFunction { + + public R apply(T service) throws KuraException; + } + + public interface ServiceConsumer { + + public void consume(T service) throws KuraException; + } + + public interface ServiceReferenceConsumer { + + public void consume(ServiceReference service, BundleContext context) throws KuraException; + } + } diff --git a/kura/pom.xml b/kura/pom.xml index 3304d676eed..22651af3aff 100644 --- a/kura/pom.xml +++ b/kura/pom.xml @@ -107,7 +107,9 @@ org.eclipse.kura.network.threat.manager org.eclipse.kura.core.tamper.detection org.eclipse.kura.log.filesystem.provider + org.eclipse.kura.rest.cloudconnection.provider org.eclipse.kura.rest.configuration.provider + org.eclipse.kura.rest.identity.provider org.eclipse.kura.rest.inventory.provider org.eclipse.kura.rest.command.provider org.eclipse.kura.rest.packages.provider @@ -126,7 +128,6 @@ org.eclipse.kura.wire.script.tools org.eclipse.kura.db.sqlite.provider org.eclipse.kura.rest.network.status.provider - org.eclipse.kura.rest.identity.provider emulator test-util diff --git a/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/AbstractRequestHandlerTest.java b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/AbstractRequestHandlerTest.java index 94510ebed80..9b793dedd1a 100644 --- a/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/AbstractRequestHandlerTest.java +++ b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/AbstractRequestHandlerTest.java @@ -29,9 +29,18 @@ public abstract class AbstractRequestHandlerTest { protected final Transport transport; protected Optional response = Optional.empty(); + protected final TransportType transportType; protected AbstractRequestHandlerTest(final Transport transport) { this.transport = transport; + + if (this.transport instanceof MqttTransport) { + this.transportType = TransportType.MQTT; + } else if (this.transport instanceof RestTransport) { + this.transportType = TransportType.REST; + } else + throw new IllegalArgumentException("Transport type must be a REST transport or a MQTT transport"); + this.transport.init(); } @@ -62,27 +71,28 @@ protected void thenResponseCodeIs(final int expectedResponseCode) { } protected void thenResponseBodyEqualsJson(final String value) { - assertEquals(Json.parse(value), Json - .parse(expectResponse().getBody() - .orElseThrow(() -> new IllegalStateException("expected response body")))); + assertEquals(Json.parse(value), Json.parse( + expectResponse().getBody().orElseThrow(() -> new IllegalStateException("expected response body")))); } protected void thenResponseBodyIsEmpty() { assertEquals(Optional.empty(), expectResponse().getBody()); } + protected void thenResponseBodyIsNotEmpty() { + assertTrue(expectResponse().getBody().isPresent()); + } + protected void thenResponseHasCookie(final String name) { final CookieManager cookieManager = expectCookieManager(); - assertTrue(cookieManager.getCookieStore().getCookies().stream() - .anyMatch(c -> c.getName().equals(name))); + assertTrue(cookieManager.getCookieStore().getCookies().stream().anyMatch(c -> c.getName().equals(name))); } protected void thenResponseDoesNotHaveCookie(final String name) { final CookieManager cookieManager = expectCookieManager(); - assertTrue(cookieManager.getCookieStore().getCookies().stream() - .noneMatch(c -> c.getName().equals(name))); + assertTrue(cookieManager.getCookieStore().getCookies().stream().noneMatch(c -> c.getName().equals(name))); } protected CookieManager expectCookieManager() { @@ -98,9 +108,12 @@ protected Response expectResponse() { } protected JsonObject expectJsonResponse() { - return Json - .parse(expectResponse().getBody() - .orElseThrow(() -> new IllegalStateException("response body is empty"))) + return Json.parse( + expectResponse().getBody().orElseThrow(() -> new IllegalStateException("response body is empty"))) .asObject(); } + + public TransportType getTransportType() { + return this.transportType; + } } diff --git a/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/TransportType.java b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/TransportType.java new file mode 100644 index 00000000000..ca821a3bf00 --- /dev/null +++ b/kura/test/org.eclipse.kura.core.testutil/src/main/java/org/eclipse/kura/core/testutil/requesthandler/TransportType.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.testutil.requesthandler; + +public enum TransportType { + + MQTT("Mqtt"), + REST("Rest"); + + private String value; + + TransportType(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + @Override + public String toString() { + return this.value; + } +} diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/META-INF/MANIFEST.MF b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..266e90bf71c --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/META-INF/MANIFEST.MF @@ -0,0 +1,28 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: org.eclipse.kura.rest.cloudconnection.provider.test +Bundle-SymbolicName: org.eclipse.kura.rest.cloudconnection.provider.test +Bundle-Version: 5.4.0 +Bundle-Vendor: Eclipse Kura +Bundle-License: Eclipse Public License v2.0 +Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" +Bundle-ActivationPolicy: lazy +Import-Package: com.google.gson;version="2.9.0", + javax.annotation;version="1.2.0", + org.eclipse.kura.core.testutil.requesthandler;version="[1.1,2.0)", + org.eclipse.kura.core.testutil.service;version="[1.0,2.0)", + org.junit;version="[4.12.0,5.0.0)", + org.junit.runner;version="[4.12.0,5.0.0)", + org.junit.runners;version="[4.12.0,5.0.0)", + org.mockito;version="[4.0.0,5.0.0)", + org.mockito.invocation;version="[4.0.0,5.0.0)", + org.mockito.stubbing;version="[4.0.0,5.0.0)", + org.osgi.framework;version="1.10.0", + org.osgi.service.cm;version="1.6.0", + org.osgi.service.useradmin;version="1.1.0", + org.osgi.util.tracker;version="1.5.2", + org.slf4j;version="1.7.25" +Fragment-Host: org.eclipse.kura.rest.cloudconnection.provider +Require-Bundle: org.eclipse.kura.http.server.manager;bundle-version="1.1.0", + org.eclipse.kura.broker.artemis.core;bundle-version="1.2.0", + org.eclipse.kura.broker.artemis.simple.mqtt;bundle-version="1.1.0" diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/build.properties b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/build.properties new file mode 100644 index 00000000000..85c4cb3c0d6 --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/build.properties @@ -0,0 +1,15 @@ +# +# 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 +# +source.. = src/main/java +bin.includes = META-INF/,\ + . diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/pom.xml b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/pom.xml new file mode 100644 index 00000000000..7179ef28d5b --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/pom.xml @@ -0,0 +1,71 @@ + + + + 4.0.0 + + + org.eclipse.kura + test + 5.4.0 + + + org.eclipse.kura.rest.cloudconnection.provider.test + eclipse-test-plugin + + + ${project.basedir}/../.. + ${project.build.directory}/site/jacoco-aggregate/jacoco.xml + + + + + + org.jacoco + jacoco-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + compiletests + test-compile + + testCompile + + + + + + org.eclipse.tycho + tycho-surefire-plugin + + classes + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + + org.eclipse.tycho + target-platform-configuration + + + + diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/test/CloudConnectionEndpointsTest.java b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/test/CloudConnectionEndpointsTest.java new file mode 100644 index 00000000000..4833703e5ba --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/java/org/eclipse/kura/internal/rest/cloudconnection/provider/test/CloudConnectionEndpointsTest.java @@ -0,0 +1,311 @@ +/******************************************************************************* + * 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.rest.cloudconnection.provider.test; + +import static org.junit.Assert.fail; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Optional; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +import org.eclipse.kura.KuraException; +import org.eclipse.kura.cloudconnection.CloudConnectionConstants; +import org.eclipse.kura.cloudconnection.factory.CloudConnectionFactory; +import org.eclipse.kura.configuration.ConfigurationService; +import org.eclipse.kura.core.testutil.requesthandler.AbstractRequestHandlerTest; +import org.eclipse.kura.core.testutil.requesthandler.MqttTransport; +import org.eclipse.kura.core.testutil.requesthandler.RestTransport; +import org.eclipse.kura.core.testutil.requesthandler.Transport; +import org.eclipse.kura.core.testutil.requesthandler.Transport.MethodSpec; +import org.eclipse.kura.core.testutil.service.ServiceUtil; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudConnectionFactoryPidAndCloudEndpointPid; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.CloudEndpointPidRequest; +import org.eclipse.kura.internal.rest.cloudconnection.provider.dto.PidAndFactoryPidAndCloudEndpointPid; +import org.eclipse.kura.rest.configuration.api.PidAndFactoryPid; +import org.eclipse.kura.rest.configuration.api.PidSet; +import org.eclipse.kura.rest.configuration.api.UpdateComponentConfigurationRequest; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import com.google.gson.Gson; + +@RunWith(Parameterized.class) +public class CloudConnectionEndpointsTest extends AbstractRequestHandlerTest { + + private static final String CLOUD_ENDPOINT_INSTANCE_TEST = "org.eclipse.kura.cloud.CloudService-test"; + + private static final String MQTT_APP_ID = "CLD-V1"; + + private static final String METHOD_SPEC_GET = "GET"; + private static final String METHOD_SPEC_POST = "POST"; + private static final String METHOD_SPEC_DELETE = "DELETE"; + private static final String MQTT_METHOD_SPEC_DEL = "DEL"; + private static final String METHOD_SPEC_PUT = "PUT"; + private static final String REST_APP_ID = "cloudconnection/v1"; + + private static CloudConnectionFactory cloudConnectionFactory; + private static ConfigurationService configurationService; + + private Gson gson = new Gson(); + + private CloudConnectionFactoryPidAndCloudEndpointPid cloudConnectionFactoryPidAndCloudEndpointPid; + private PidAndFactoryPidAndCloudEndpointPid pidAndFactoryPidAndCloudEndpointPid; + private PidAndFactoryPid pidAndFactoryPid; + private PidSet pidSet; + + private UpdateComponentConfigurationRequest updateComponentConfigurationRequest; + private CloudEndpointPidRequest cloudEndpointPidRequest; + + private static final String EXPECTED_GET_STACK_COMPONENT_PIDS_RESPONSE = new Scanner( + CloudConnectionEndpointsTest.class.getResourceAsStream("/getStackComponentPidsResponse.json"), "UTF-8") + .useDelimiter("\\A").next().replace(" ", ""); + + private static final String UPDATE_COMPONENT_CONFIGURATION_REQUEST = new Scanner( + CloudConnectionEndpointsTest.class.getResourceAsStream("/updateConfigurationRequest.json"), "UTF-8") + .useDelimiter("\\A").next().replace(" ", ""); + + private static final String EXPECTED_IS_ENDPOINT_CONNECTED_RESPONSE = new Scanner( + CloudConnectionEndpointsTest.class.getResourceAsStream("/isConnectedResponse.json"), "UTF-8") + .useDelimiter("\\A").next().replace(" ", ""); + + @Parameterized.Parameters(name = "{0}") + public static Collection transports() { + return Arrays.asList(new MqttTransport(MQTT_APP_ID), new RestTransport(REST_APP_ID)); + } + + public CloudConnectionEndpointsTest(Transport transport) { + super(transport); + + } + + @BeforeClass + public static void setup() { + try { + configurationService = ServiceUtil.trackService(ConfigurationService.class, Optional.empty()).get(30, + TimeUnit.SECONDS); + cloudConnectionFactory = ServiceUtil.trackService(CloudConnectionFactory.class, Optional.empty()).get(30, + TimeUnit.SECONDS); + cloudConnectionFactory.createConfiguration(CLOUD_ENDPOINT_INSTANCE_TEST); + } catch (Exception e) { + fail("Unable to create the test CloudEndpoint"); + } + } + + @Test + public void shouldGetCloudComponentInstances() { + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), "/instances"); + + thenRequestSucceeds(); + thenResponseBodyIsNotEmpty(); + } + + @Test + public void shouldGetStackComponentPids() { + givenCloudConnectionFactoryPidAndCloudEndpointPid("org.eclipse.kura.cloud.CloudService", + CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/cloudEndpoint/stackComponentPids", + gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid)); + + thenRequestSucceeds(); + thenResponseBodyEqualsJson(EXPECTED_GET_STACK_COMPONENT_PIDS_RESPONSE); + } + + @Test + public void shouldCreateCloudEndpoint() { + givenCloudConnectionFactoryPidAndCloudEndpointPid("org.eclipse.kura.cloud.CloudService", + "org.eclipse.kura.cloud.CloudService-createTest" + this.getTransportType()); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/cloudEndpoint", + gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldDeleteCloudEndpoint() { + givenExistingCloudEndpoint("org.eclipse.kura.cloud.CloudService-toDelete" + this.getTransportType()); + givenCloudConnectionFactoryPidAndCloudEndpointPid("org.eclipse.kura.cloud.CloudService", + "org.eclipse.kura.cloud.CloudService-toDelete" + this.getTransportType()); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), "/cloudEndpoint", + gson.toJson(this.cloudConnectionFactoryPidAndCloudEndpointPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldGetCloudComponentFactories() { + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_GET), "/factories"); + + thenRequestSucceeds(); + thenResponseBodyIsNotEmpty(); + } + + @Test + public void shouldCreatePublisherInstance() { + givenPidAndFactoryPidAndCloudEndpointPid("test-pub-" + this.getTransportType(), + "org.eclipse.kura.cloud.publisher.CloudPublisher", CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/pubSub", + gson.toJson(this.pidAndFactoryPidAndCloudEndpointPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldCreateSubscriberInstance() { + givenPidAndFactoryPidAndCloudEndpointPid("test-sub-" + this.getTransportType(), + "org.eclipse.kura.cloud.subscriber.CloudSubscriber", CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/pubSub", + gson.toJson(this.pidAndFactoryPidAndCloudEndpointPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldDeletePublisherInstance() { + givenPubSubInstance("pub-to-delete-" + this.getTransportType(), + "org.eclipse.kura.cloud.publisher.CloudPublisher", CLOUD_ENDPOINT_INSTANCE_TEST); + givenPid("pub-to-delete-" + this.getTransportType()); + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), "/pubSub", + gson.toJson(this.pidAndFactoryPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldDeleteSubscriberInstance() { + givenPubSubInstance("sub-to-delete-" + this.getTransportType(), + "org.eclipse.kura.cloud.subscriber.CloudSubscriber", CLOUD_ENDPOINT_INSTANCE_TEST); + givenPid("sub-to-delete-" + this.getTransportType()); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_DELETE, MQTT_METHOD_SPEC_DEL), "/pubSub", + gson.toJson(this.pidAndFactoryPid)); + + thenRequestSucceeds(); + } + + @Test + public void shouldGetConfigurations() { + givenPidSet(CLOUD_ENDPOINT_INSTANCE_TEST, "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test", // + "org.eclipse.kura.data.DataService-test"); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/configurations", gson.toJson(this.pidSet)); + + thenRequestSucceeds(); + thenResponseBodyIsNotEmpty(); + } + + @Test + public void shouldUpdateStackComponentConfigurations() { + + givenUpdateComponentConfigurationRequest(UPDATE_COMPONENT_CONFIGURATION_REQUEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_PUT), "/configurations", + gson.toJson(this.updateComponentConfigurationRequest)); + + thenRequestSucceeds(); + } + + @Test + public void shouldConnectEndpoint() { + givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/cloudEndpoint/connect", + gson.toJson(this.cloudEndpointPidRequest)); + + thenRequestSucceeds(); + } + + @Test + public void shouldDisconnectEndpoint() { + givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/cloudEndpoint/disconnect", + gson.toJson(this.cloudEndpointPidRequest)); + + thenRequestSucceeds(); + } + + @Test + public void shouldCheckEndpointStatus() { + givenCloudEndpointPidRequest(CLOUD_ENDPOINT_INSTANCE_TEST); + + whenRequestIsPerformed(new MethodSpec(METHOD_SPEC_POST), "/cloudEndpoint/isConnected", + gson.toJson(this.cloudEndpointPidRequest)); + + thenRequestSucceeds(); + thenResponseBodyEqualsJson(EXPECTED_IS_ENDPOINT_CONNECTED_RESPONSE); + } + + private void givenCloudEndpointPidRequest(String pid) { + this.cloudEndpointPidRequest = new CloudEndpointPidRequest(pid); + } + + private void givenCloudConnectionFactoryPidAndCloudEndpointPid(String cloudConnectionFactoryPid, + String cloudEndpointPid) { + this.cloudConnectionFactoryPidAndCloudEndpointPid = new CloudConnectionFactoryPidAndCloudEndpointPid( + cloudConnectionFactoryPid, cloudEndpointPid); + } + + private void givenUpdateComponentConfigurationRequest(String jsonFileContent) { + this.updateComponentConfigurationRequest = this.gson.fromJson(jsonFileContent, + UpdateComponentConfigurationRequest.class); + + } + + private void givenPidAndFactoryPidAndCloudEndpointPid(String pid, String factoryPid, String cloudEndpointPid) { + this.pidAndFactoryPidAndCloudEndpointPid = new PidAndFactoryPidAndCloudEndpointPid(pid, factoryPid, + cloudEndpointPid); + } + + private void givenPid(String pid) { + this.pidAndFactoryPid = new PidAndFactoryPid(pid); + } + + private void givenPidSet(String... pids) { + this.pidSet = new PidSet(new HashSet(Arrays.asList(pids))); + } + + private void givenExistingCloudEndpoint(String cloudEndpointPid) { + try { + cloudConnectionFactory.createConfiguration(cloudEndpointPid); + + } catch (KuraException e) { + e.printStackTrace(); + fail("Unable to create the test CloudService"); + } + } + + private void givenPubSubInstance(String pid, String factoryPid, String cloudEndpointPid) { + try { + configurationService.createFactoryConfiguration(factoryPid, pid, Collections.singletonMap( + CloudConnectionConstants.CLOUD_ENDPOINT_SERVICE_PID_PROP_NAME.value(), cloudEndpointPid), true); + } catch (KuraException e) { + e.printStackTrace(); + fail("Unable to create pubSub instance"); + } + + } + +} diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/getStackComponentPidsResponse.json b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/getStackComponentPidsResponse.json new file mode 100644 index 00000000000..e5d30e9d0e9 --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/getStackComponentPidsResponse.json @@ -0,0 +1,7 @@ +{ + "pids": [ + "org.eclipse.kura.cloud.CloudService-test", + "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test", + "org.eclipse.kura.data.DataService-test" + ] +} \ No newline at end of file diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/isConnectedResponse.json b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/isConnectedResponse.json new file mode 100644 index 00000000000..6aa99142410 --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/isConnectedResponse.json @@ -0,0 +1,3 @@ +{ + "connected": false +} \ No newline at end of file diff --git a/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/updateConfigurationRequest.json b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/updateConfigurationRequest.json new file mode 100644 index 00000000000..1af183d045b --- /dev/null +++ b/kura/test/org.eclipse.kura.rest.cloudconnection.provider.test/src/main/resources/updateConfigurationRequest.json @@ -0,0 +1,70 @@ +{ + "configs": [ + { + "pid": "org.eclipse.kura.core.data.transport.mqtt.MqttDataTransport-test", + "properties": { + "broker-url": { + "type": "STRING", + "value": "mqtt://mqtt.eclipseprojects.io:1883" + }, + "topic.context.account-name": { + "type": "STRING", + "value": "account-name-testX2" + }, + "username": { + "type": "STRING", + "value": "username" + }, + "password": { + "type": "PASSWORD", + "value": "Placeholder" + }, + "client-id": { + "type": "STRING", + "value": "" + }, + "keep-alive": { + "type": "INTEGER", + "value": 30 + }, + "timeout": { + "type": "INTEGER", + "value": 20 + }, + "clean-session": { + "type": "BOOLEAN", + "value": true + }, + "lwt.topic": { + "type": "STRING", + "value": "$EDC/#account-name/#client-id/MQTT/LWT" + }, + "lwt.payload": { + "type": "STRING", + "value": "" + }, + "lwt.qos": { + "type": "INTEGER", + "value": 0 + }, + "lwt.retain": { + "type": "BOOLEAN", + "value": false + }, + "in-flight.persistence": { + "type": "STRING", + "value": "memory" + }, + "protocol-version": { + "type": "INTEGER", + "value": 4 + }, + "SslManagerService.target": { + "type": "STRING", + "value": "(kura.service.pid=org.eclipse.kura.ssl.SslManagerService)" + } + } + } + ], + "takeSnapshot" : true +} \ No newline at end of file diff --git a/kura/test/pom.xml b/kura/test/pom.xml index 7cc690f07b6..6fc937291e8 100644 --- a/kura/test/pom.xml +++ b/kura/test/pom.xml @@ -907,12 +907,12 @@ org.eclipse.kura.net.admin.firewall.test org.eclipse.kura.nm.test org.eclipse.kura.net.configuration.test - org.eclipse.kura.rest.asset.provider.test org.eclipse.kura.protocol.modbus.test org.eclipse.kura.stress.test org.eclipse.kura.test org.eclipse.kura.util.test org.eclipse.kura.watchdog.criticaltest + org.eclipse.kura.wire.ai.component.provider.test org.eclipse.kura.wire.component.provider.test org.eclipse.kura.wire.h2db.component.provider.test org.eclipse.kura.wire.db.component.provider.test @@ -925,25 +925,28 @@ org.eclipse.kura.useradmin.store.test org.eclipse.kura.core.keystore.test org.eclipse.kura.log.filesystem.provider.test + + org.eclipse.kura.rest.provider.test + org.eclipse.kura.rest.asset.provider.test org.eclipse.kura.rest.configuration.provider.test + org.eclipse.kura.rest.cloudconnection.provider.test org.eclipse.kura.rest.command.provider.test + org.eclipse.kura.rest.identity.provider.test org.eclipse.kura.rest.inventory.provider.test + org.eclipse.kura.rest.network.status.provider.test org.eclipse.kura.rest.packages.provider.test org.eclipse.kura.rest.position.provider.test org.eclipse.kura.rest.security.provider.test - org.eclipse.kura.rest.identity.provider.test org.eclipse.kura.rest.service.listing.provider.test org.eclipse.kura.rest.system.provider.test org.eclipse.kura.rest.wire.provider.test + org.eclipse.kura.util.test.driver org.eclipse.kura.container.orchestration.provider.test - org.eclipse.kura.wire.ai.component.provider.test org.eclipse.kura.container.provider.test org.eclipse.kura.ai.triton.server.test - org.eclipse.kura.rest.provider.test org.eclipse.kura.db.sqlite.provider.test org.eclipse.kura.message.store.provider.test - org.eclipse.kura.rest.network.status.provider.test