From 0a86bc452907d468e083a6e7fb08666d7da60858 Mon Sep 17 00:00:00 2001 From: Predix Robot Date: Fri, 26 May 2017 11:27:36 -0700 Subject: [PATCH] Release 1.0.0 --- .gitignore | 6 + COPYRIGHT.md | 1 + LICENSE.md | 64 ++ README.md | 115 +++- config/application.properties | 41 ++ config/kit-service-tinfoil-swagger.json | 333 ++++++++++ images/javadoc.png | Bin 0 -> 6430 bytes images/pages.jpg | Bin 0 -> 4203 bytes manifest.yml | 26 + manifest.yml.template | 22 + pom.xml | 343 +++++++++++ .../solsvc/kitservice/boot/Application.java | 287 +++++++++ .../kitservice/boot/AuthenticationFilter.java | 157 +++++ .../boot/ErrorResponseController.java | 67 ++ .../solsvc/kitservice/boot/EventError.java | 127 ++++ .../kitservice/boot/SwaggerConfiguration.java | 40 ++ .../kitservice/boot/utils/FdhUtils.java | 194 ++++++ .../controller/HelloController.java | 53 ++ .../kitservice/controller/KitController.java | 362 +++++++++++ .../error/DeviceRegistrationError.java | 76 +++ .../kitservice/manager/BaseManager.java | 112 ++++ .../kitservice/manager/DeviceManager.java | 396 ++++++++++++ .../manager/GroupManagementService.java | 196 ++++++ .../solsvc/kitservice/model/KitGroup.java | 71 +++ .../kitservice/model/RegisterDevice.java | 238 ++++++++ .../solsvc/kitservice/model/UserGroup.java | 115 ++++ .../validator/RegisterDeviceValidation.java | 113 ++++ .../META-INF/application-security.xml | 67 ++ .../resources/application-default.properties | 14 + src/main/resources/application.properties | 24 + .../asset-model/device-asset-tags.json | 84 +++ .../asset-model/kit-asset-model-metadata.json | 47 ++ .../asset-model/kit-asset-model.json | 114 ++++ .../resources/asset-model/model-tags.json | 41 ++ .../resources/javadoc-override/stylesheet.css | 573 ++++++++++++++++++ src/main/resources/templates/index.html | 15 + .../service/AbstractBaseControllerIT.java | 32 + .../solsvc/service/HelloControllerIT.java | 69 +++ .../solsvc/service/KitControllerIT.java | 491 +++++++++++++++ 39 files changed, 5124 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 COPYRIGHT.md create mode 100644 LICENSE.md create mode 100644 config/application.properties create mode 100644 config/kit-service-tinfoil-swagger.json create mode 100644 images/javadoc.png create mode 100644 images/pages.jpg create mode 100644 manifest.yml create mode 100644 manifest.yml.template create mode 100644 pom.xml create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/Application.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/AuthenticationFilter.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/ErrorResponseController.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/EventError.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/SwaggerConfiguration.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/boot/utils/FdhUtils.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/controller/HelloController.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/controller/KitController.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/error/DeviceRegistrationError.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/manager/BaseManager.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/manager/DeviceManager.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/manager/GroupManagementService.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/model/KitGroup.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/model/RegisterDevice.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/model/UserGroup.java create mode 100644 src/main/java/com/ge/predix/solsvc/kitservice/validator/RegisterDeviceValidation.java create mode 100644 src/main/resources/META-INF/application-security.xml create mode 100644 src/main/resources/application-default.properties create mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/asset-model/device-asset-tags.json create mode 100644 src/main/resources/asset-model/kit-asset-model-metadata.json create mode 100644 src/main/resources/asset-model/kit-asset-model.json create mode 100644 src/main/resources/asset-model/model-tags.json create mode 100644 src/main/resources/javadoc-override/stylesheet.css create mode 100644 src/main/resources/templates/index.html create mode 100644 src/test/java/com/ge/predix/solsvc/service/AbstractBaseControllerIT.java create mode 100644 src/test/java/com/ge/predix/solsvc/service/HelloControllerIT.java create mode 100644 src/test/java/com/ge/predix/solsvc/service/KitControllerIT.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7414ddf --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/target/ +.classpath +.project +.settings/ +src/main/resources/static/javadoc/ +/.springBeans diff --git a/COPYRIGHT.md b/COPYRIGHT.md new file mode 100644 index 0000000..2b9ec0a --- /dev/null +++ b/COPYRIGHT.md @@ -0,0 +1 @@ +The dependencies in this project are resolved by Maven pom.xml. Copyrights from those projects are included [here](http://predixdev.github.io/predix-rmd-ref-app/copyright.html). This list may be a superset of projects actually referenced by this project. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..2b0ac50 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,64 @@ +###GE Software Development License Agreement – General Release + +THIS SOFTWARE LICENSE AGREEMENT (the “License”) describes the rights granted by the General Electric Company, operating through GE Digital (also referred to as “GE Software”), located at 2623 Camino Ramon, San Ramon, CA 94583 (herein referred to as “Licensor”) to any entity (the “Licensee”) receiving a copy of any of the following GE Digital development materials: Predix DevBox; Predix Reference Application (“RefApp”); Predix Dashboard Seed; Predix Px, Predix Security Service redistributable .jar files; Predix Machine redistributable .jar files; and Predix Machine SDK . These materials may include scripts, compiled code, supporting components, and documentation and are collectively referred to as the “Licensed Programs”. Both Licensor and Licensee are referred to hereinafter as a “Party” and collectively as the “Parties” to this License + +### Section 1 – Conditional Grant. +No Licensee is required to accept this License for use of the Licensed Programs. In the absence of a signed license agreement between Licensor and Licensee specifying alternate terms, any use of the Licensed Programs by the Licensee shall be considered acceptance of these terms. The Licensed Programs are copyrighted and are licensed, not sold, to you. If you are not willing to be bound by the terms of this License, do not install, copy or use the Licensed Programs. If you received this software from any source other than the Licensor, your access to the Licensed Programs is NOT permitted under this License, and you must delete the software and any copies from your systems. + +###Section 2 – Warranty Disclaimer. +NO WARRANTIES. LICENSOR AND OUR AFFILIATES, RESELLERS, DISTRIBUTORS, AND VENDORS, MAKE NO WARRANTIES, EXPRESS OR IMPLIED, GUARANTEES OR CONDITIONS WITH RESPECT TO USE OF THE LICENSED PROGRAMS. LICENSEE’S USE OF ALL SUCH PROGRAMS ARE AT LICENSEE’S AND CUSTOMERS’ OWN RISK. LICENSOR PROVIDES THE LICENSED PROGRAMS ON AN “AS IS” BASIS “WITH ALL FAULTS” AND “AS AVAILABLE.” LICENSOR DOES NOT GUARANTEE THE ACCURACY OR TIMELINESS OF INFORMATION AVAILABLE FROM, OR PROCESSED BY, THE LICENSED PROGRAMS. TO THE EXTENT PERMITTED UNDER LAW, LICENSOR EXCLUDES ANY IMPLIED WARRANTIES, INCLUDING FOR MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, AND NON-INFRINGEMENT. NO GUARANTEE OF UNINTERRUPTED, TIMELY, SECURE, OR ERROR-FREE OPERATION IS MADE. + +THESE LICENSED PROGRAMS MAY BE USED AS PART OF A DEVELOPMENT ENVIRONMENT, AND MAY BE COMBINED WITH OTHER CODE BY END-USERS. LICENSOR IS NOT ABLE TO GUARANTEE THAT THE LICENSED PROGRAMS WILL OPERATE WITHOUT DEFECTS WHEN USED IN COMBINATION WITH END-USER SOFTWARE. LICENSEE IS ADVISED TO SAFEGUARD IMPORTANT DATA, TO USE CAUTION, AND NOT TO RELY IN ANY WAY ON THE CORRECT FUNCTIONING OR PERFORMANCE OF ANY COMBINATION OF END-USER SOFTWARE AND THE LICENSED PROGRAMS AND/OR ACCOMPANYING MATERIALS. LICENSEE IS ADVISED NOT TO USE ANY COMBINATION OF LICENSED PROGRAMS AND END-USER PROVIDED SOFTWARE IN A PRODUCTION ENVIRONMENT WITHOUT PRIOR SUITABILITY AND DEFECT TESTING. + +###Section 3 – Feedback. +It is expressly understood, acknowledged and agreed that you may provide GE reasonable suggestions, comments and feedback regarding the Software, including but not limited to usability, bug reports and test results, with respect to Software testing (collectively, "Feedback"). If you provide such Feedback to GE, you shall grant GE the following worldwide, non-exclusive, perpetual, irrevocable, royalty free, fully paid up rights: + + a. to make, use, copy, modify, sell, distribute, sub-license, and create derivative works of, the Feedback as part of any product, technology, service, specification or other documentation developed or offered by GE or any of its affiliates (individually and collectively, "GE Products"); + b. to publicly perform or display, import, broadcast, transmit, distribute, license, offer to sell, and sell, rent, lease or lend copies of the Feedback (and derivative works thereof) as part of any GE Product; + c. solely with respect to Licensee's copyright and trade secret rights, to sublicense to third parties the foregoing rights, including the right to sublicense to further third parties; and + d. to sublicense to third parties any claims of any patents owned or licensable by Licensee that are necessarily infringed by a third party product, technology or service that uses, interfaces, interoperates or communicates with the Feedback or portion thereof incorporated into a GE Product, technology or service. Further, you represent and warrant that your Feedback is not subject to any license terms that would purport to require GE to comply with any additional obligations with respect to any GE Products that incorporate any Feedback. + +###Section 4 – Reserved + +###Section 5 – Limitation of Liability. +LIABILITY ARISING UNDER THIS LICENSE, WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), SHALL BE LIMITED TO DIRECT, OBJECTIVELY MEASURABLE DAMAGES. LICENSOR SHALL HAVE NO LIABILITY TO THE OTHER PARTY OR TO ANY THIRD PARTY, FOR ANY INCIDENTAL, PUNITIVE, INDIRECT, OR CONSEQUENTIAL DAMAGES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. LIABILITY FOR ANY SOFTWARE LICENSED FROM THIRD PARTIES FOR USE WITH THE SERVICES IS EXPLICILTLY DISCLAIMED AND LIMITED TO THE MAXIMUM EXTENT PERMITTED BY LAW. + +Notwithstanding anything to the contrary, the aggregate liability of Licensor and its suppliers under this License shall not exceed the total amounts paid by Licensee to Licensor hereunder during the one-year period immediately preceding the event which gave rise to the claims. + +###Section 6 – License. + +A. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants Licensee a worldwide, perpetual, royalty-free, non-exclusive license to: + + 1. install the Licensed Programs on Licensee’s premises, and permit Licensee’s users to use the Licensed Programs so installed, solely for Licensee’s own development, testing, demonstration, staging, and production of Licensee’s own software that makes use of the Licensed Programs in a way that adds substantial functionality not present in the Licensed Programs (the result, a “Licensee Application”); + + 2. permit Licensee to permit third-party hosts (“Hosts”) to install the Licensee Application on such Hosts’ respective premises on Licensee’s behalf, and permit Licensee’s users to access and use the Licensed Programs so installed, solely for Licensee’s own development, testing, demonstration, staging and production purposes + + 3. install the Licensee Application on Licensee’s own premises and permit its own users to use the Licensee Application so installed on the same terms as sub-sections (i) and (ii) above. + +B. For the purposes of this License, the right to “use” the Licensed Programs shall include the right to utilize, run, access, store, copy, test or display the Licensed Programs. No right or license is granted or agreed to be granted to disassemble or decompile any Licensed Programs furnished in object code form, and Licensee agrees not to engage in any such conduct unless permitted by law. Reverse engineering of Licensed Programs provided in object code form is prohibited, unless such a right is explicitly granted by any explicit license subject to sub-section (d) below or as a matter of law, and then only to the extent explicitly permitted. Licensor shall have no obligation to support any such reverse engineering, any product or derivative of such reverse engineering, or any use of the Licensed Programs with any modified versions of any of their components under this License. + +C. Licensee shall ensure that any Licensee Applications incorporate the Licensed Programs in such a way as to prevent third parties (other than Hosts) from viewing the code of the Licensed Programs or gaining access to any programmatic interface or other hidden aspect of the Licensed Programs. Licensee shall also restrict distribution of the Licensed Programs, including as part of Licensee Applications, to only those parties who are notified of, and subject to, an enforceable obligation to refrain from any of the prohibited activities listed herein, such as reverse engineering or disassembling the Licensed Programs. + + +D. Use of some open source and third party software applications or components included in or accessed through the Licensed Programs may be subject to other terms and conditions found in a separate license agreement, terms of use or “Notice” file located at the download page. The Licensed Programs are accompanied by additional software components solely to enable the Licensed Programs to operate as designed. Licensee is not permitted to use such additional software independently of the Licensed Programs unless Licensee secures a separate license for use from the named vendor. Do not use any third party code unless you agree with the applicable license terms for that code. + +E. Title. Title to and ownership of the Licensed Programs shall at all times remain with Licensor. + +###Section 7 – Termination. + +A) The Licensor reserves the right to cease distribution and grant of further licenses to any or all of the Licensed Programs at any time in its sole discretion. + +B) The Licensor reserves the right to at any time and at its sole discretion provide updated versions of any or all of the Licensed Programs that supercede and replace the prior version of that Licensed Program. + +C) Your license rights under Section 6 are effective until terminated as described below: + +i) This license and all rights under it will terminate or cease to be effective without notice if Licensee breaches the terms of the License and does not correct or remedy such breach promptly. + +ii) Notwithstanding the foregoing, Licensee may terminate this License at any time for any reason or no reason by providing the Licensor written notice thereof. + +D) Upon any expiration or termination of this License, the rights and licenses granted to you under this License shall immediately terminate, and you shall immediately cease using and delete the Licensed Programs. Licensee Applications based upon the Licensed Programs (see Section 6(a) above) are not subject to this limitation. + +In the event of any expiration or termination of this Licensee, any Confidentiality provision, disclaimers of GE’s representations and warranties, choice of applicable law and limitations of GE’s liability shall survive. + +###Section 8 – Applicable Law. +The License shall be governed by and interpreted in accordance with the substantive law of the State of California, U.S.A., excluding its conflicts of law provisions, and by the courts of that state. diff --git a/README.md b/README.md index 68704d1..3356743 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,113 @@ -# kit-service -Backend for Predix Dev Kits + + view javadoc +  + + view github pages + + +Kit Service +============== + +Kit Service is the back-end microservice that provides the rest end points to register device, get device, get device configurations. + +## Kit Service + + +##To Download and Push Kit Service + +1. Download a [DevBox](https://www.predix.io/catalog/other-resources/devbox.html) and launch it in Virtual Box or install the [Dependencies](#dependencies) + +1. [Prepare your environment](#preparation) and follow the steps below to get up and running on Cloud Foundry. + +1. Download the project + ``` + $ git clone https://github.com/PredixDev/predix-kit.git + + $ cd predix-kit + + $ mvn clean package + + note: mvn clean install may run integration tests against services you may not have set up yet + ``` +1. To load in eclipse (you may skip to 'Push to Cloud' if desired) + + Vanilla [Eclipse](https://www.eclipse.org/downloads) or [Eclipse STS - Springsource Tool Suite(https://spring.io/tools/sts/all) are both supported + ``` + $ mvn eclipse:clean eclipse:eclipse + + File/Import/General/Existing Projects/Browse to predix-microservice-cf dir + + Check the box 'Search for nested projects' + ``` +1. Try it out locally + ``` + in Eclipse - Right Click predix-kit project / Run As / Application + in Eclise STS - Right Click predix-kit project / Run As / Spring Boot Application + + Visit service at http://localhost:9092 - this page provides health check, swagger documentation and Java documentation links. + Visit service at http://localhost:9092/device - with Authorization Header + This endpoint checks the token for application-scope to determine application specific scope authorization to allow users to register the device and model the device with Predix Asset service. + + ``` +1. Push to cloud + + Take a look at the [kit-service manifest.yml](manifest.yml) which provides properties and instructions for [pushing cloud foundry apps](https://docs.cloudfoundry.org/devguide/deploy-apps/manifest.html) + ``` + $ cf push + + visit http://(cloud-url-here)/api/health - get the url from the output of cf push + ``` + +##Troubleshooting +If you encounter a github acct/password issue then contact predixgithubaccount@ge.com. + +If you encounter a [corporate proxy issue](https://github.com/PredixDev/predix-rmd-ref-app/blob/master/docs/proxy.md#proxy), you might need to set up your env vars as required by your IT department. + +If you encounter a maven or artifactory account issue, add your predix.io username and encrypted password to a maven ~/.m2/[settings.xml](docs/settings.xml) file on your laptop. It should be setup already if in a [DevBox](https://www.predix.io/catalog/other-resources/devbox.html). + +##Preparation +Predix Kit service accesses code repos at https://github.com/PredixDev. + +The best experience is to use a [DevBox](https://www.predix.io/catalog/other-resources/devbox.html) which has all the tools and settings pre-installed. +* In DevBox, + * add your encrypted predix.io username and password to the ~/.m2/settings.xml +by replacing predixuser@ge.com with your Predix.io user and pass. + + * to avoid entering user/pass several times, run this command to cache it + ``` + git config --replace-all --global credential.helper 'cache --timeout=7200' + ``` + * OSX: To enable Copy/Paste using Left Command key. + ``` + On Host: Please choose VirtualBox/Preferences/Input/Virtual Machine/Host Key Combination. + Set to Right ⌘. + On VM: Choose System/Preference/Keyboard/Layouts/Layout Options/Alt/Win Key Behavior/Ctrl is mapped to Win Keys(and the usual Ctrl keys) + ``` + + >We have a second DevBox for GE employees which helps with corporate proxy settings. + + >In your own IT environment you may need to configure the [proxy](docs/proxy.md) settings Environment variables within the VM or your own laptop. + +* For non-DevBox users, + For users wanting to install all the tools, please reference the DevBox settings, and also ensure you have the prerequisites installed from Predix.io [Getting Started](https://www.predix.io/docs/?b=#Uva9INX3) documentation and the [RMD Reference App Dependencies](https://github.com/PredixDev/predix-rmd-ref-app#dependencies). + + * add your encrypted predix.io username and password to the ~/.m2/settings.xml +by replacing predixuser@ge.com with your Predix.io user and pass. + + * to avoid entering user/pass several times, run this command to cache it + ``` + git config --global credential.helper cache --timeout=7200 + ``` + +##Dependencies +If you are not using DevBox, ensure your development environment is configured with the tools listed here. + +|Required | Version | Note | +| ------------- | :----- | :----- | +| Java | 8 | | +| GitHub Acct | n/a | logged in | +| Git | latest | | +| Maven | latest | https://artifactory.predix.io/artifactory/PREDIX-EXT | +| CloudFoundry ClI | 6.12.2 | https://github.com/cloudfoundry/cli/tree/v6.12.2#downloads. There is bug on this page, so you have to manually get the URL and the add "&version=6.12.2". For example for Windows32 it would look like this...https://cli.run.pivotal.io/stable?release=windows32&source=github&version=6.12.2 | + +[![Analytics](https://ga-beacon.appspot.com/UA-82773213-1/kit-service/readme?pixel)](https://github.com/PredixDev) diff --git a/config/application.properties b/config/application.properties new file mode 100644 index 0000000..720fd86 --- /dev/null +++ b/config/application.properties @@ -0,0 +1,41 @@ +#properties for running locally or for unit tests +logging.level.root=INFO +logging.level.org.springframework=INFO +logging.level.org.springframework.security=INFO +logging.level.com.ge.predix.solsvc.kitservice=DEBUG +#/config/application.properties are local ovverrides to src/main/resources(aka classpath)/application.properties +server.port=9092 + +spring.profiles.active=local,asset + +predix.oauth.proxyHost=sjc1intproxy01.crd.ge.com +predix.oauth.proxyPort=8080 + +predix.oauth.issuerId.url=https://92c10ab6-9ed3-4daf-a1b7-b71207885eb1.predix-uaa-training.run.aws-usw02-pr.ice.predix.io/oauth/token +predix.oauth.clientId=app_client_id:secret +#for debugging purposes, set to a high value +predix.rest.defaultSocketTimeout=500000 + +springfox.documentation.swagger.v2.path=/ +java.docs.url=https://predixdev.github.io/kit-service +accessTokenEndpointUrl=${predix.oauth.issuerId.url} + +predix.asset.restHost=predix-asset.run.aws-usw02-pr.ice.predix.io +predix.asset.zoneid=67e1d772-4ed8-4ae7-bf26-1b4351f64cd0 + +#timeseries details +predix.timeseries.queryUrl=https://time-series-store-predix.run.aws-usw02-pr.ice.predix.io/v1/datapoints +predix.timeseries.zoneid=743e1d4a-e546-4e77-a22c-f775ecf85288 +predix.timeseries.websocket.uri=wss://gateway-predix-data-services.run.aws-usw02-pr.ice.predix.io/v1/stream/messages +predix.timeseries.websocket.pool.maxIdle=5 +predix.timeseries.websocket.pool.maxActive=5 +predix.timeseries.websocket.pool.maxWait=8000 + +endpoints.beans.enabled=true +endpoints.info.enabled=true + +register.device.deactivation=60 + +kit.webapp.url=https://kit-cloud-poc.run.aws-usw02-pr.ice.predix.io +kit.device.credentials=ZGV2aWNlX2NsaWVudF9pZDpzZWNyZXQ= + diff --git a/config/kit-service-tinfoil-swagger.json b/config/kit-service-tinfoil-swagger.json new file mode 100644 index 0000000..7d48963 --- /dev/null +++ b/config/kit-service-tinfoil-swagger.json @@ -0,0 +1,333 @@ +{ + "swagger": "2.0", + "info": { + "description": "Kit Service", + "version": "1.1.6", + "title": "Kit Service" + }, + "host": "kit-service-tinfoil.run.aws-usw02-dev.ice.predix.io", + "basePath": "/", + "tags": [{ + "name": "kit-controller", + "description": "Kit Controller" + }], + "schemes": [ + "https" + ], + "paths": { + "/device/": { + "get": { + "tags": ["kit-controller"], + "summary": "getDevices", + "operationId": "getDevicesUsingGET", + "consumes": ["application/json"], + "produces": ["*/*"], + "parameters": [{ + "name": "Authorization", + "in": "header", + "description": "Authorization", + "required": true, + "type": "string" + }], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RegisterDevice" + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/device/register": { + "post": { + "tags": ["kit-controller"], + "summary": "registerDevice", + "operationId": "registerDeviceUsingPOST", + "consumes": ["application/json"], + "produces": ["*/*"], + "parameters": [{ + "in": "body", + "name": "device", + "description": "device", + "required": true, + "schema": { + "$ref": "#/definitions/RegisterDevice" + } + }, { + "name": "Authorization", + "in": "header", + "description": "Authorization", + "required": true, + "type": "string" + }], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object" + } + }, + "201": { + "description": "Created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/device/{deviceId}": { + "get": { + "tags": ["kit-controller"], + "summary": "getDevice", + "operationId": "getDeviceUsingGET", + "consumes": ["application/json"], + "produces": ["*/*"], + "parameters": [{ + "name": "deviceId", + "in": "path", + "description": "deviceId", + "required": true, + "type": "string" + }, { + "name": "Authorization", + "in": "header", + "description": "Authorization", + "required": true, + "type": "string" + }], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + }, + "put": { + "tags": ["kit-controller"], + "summary": "updateRegisterDevice", + "operationId": "updateRegisterDeviceUsingPUT", + "consumes": ["application/json"], + "produces": ["*/*"], + "parameters": [{ + "name": "deviceId", + "in": "path", + "description": "deviceId", + "required": true, + "type": "string" + }, { + "in": "body", + "name": "device", + "description": "device", + "required": true, + "schema": { + "$ref": "#/definitions/RegisterDevice" + } + }, { + "name": "Authorization", + "in": "header", + "description": "Authorization", + "required": true, + "type": "string" + }], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object" + } + }, + "201": { + "description": "Created" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + } + } + } + }, + "definitions": { + "AssetTag": { + "type": "object", + "properties": { + "alertStatusUri": { + "type": "string" + }, + "edgeDatasource": { + "$ref": "#/definitions/EdgeDatasource" + }, + "hiAlarmThreshold": { + "type": "number", + "format": "double" + }, + "hiQualityThreshold": { + "type": "number", + "format": "double" + }, + "isKpi": { + "type": "string" + }, + "label": { + "type": "string" + }, + "lastCalibrated": { + "$ref": "#/definitions/XMLGregorianCalendar" + }, + "loAlarmThreshold": { + "type": "number", + "format": "double" + }, + "loQualityThreshold": { + "type": "number", + "format": "double" + }, + "locationUUID": { + "type": "string" + }, + "tagUri": { + "type": "string" + }, + "timeseriesDatasource": { + "$ref": "#/definitions/TimeseriesDatasource" + }, + "unit": { + "type": "string" + } + } + }, + "XMLGregorianCalendar": { + "type": "object", + "properties": { + "day": { + "type": "integer", + "format": "int32" + }, + "fractionalSecond": { + "type": "number", + "format": "double" + }, + "hour": { + "type": "integer", + "format": "int32" + }, + "millisecond": { + "type": "integer", + "format": "int32" + }, + "minute": { + "type": "integer", + "format": "int32" + }, + "month": { + "type": "integer", + "format": "int32" + }, + "second": { + "type": "integer", + "format": "int32" + }, + "timezone": { + "type": "integer", + "format": "int32" + } + } + }, + "TimeseriesDatasource": { + "type": "object", + "properties": { + "tag": { + "type": "string" + } + } + }, + "RegisterDevice": { + "type": "object", + "properties": { + "activationDate": { + "type": "string" + }, + "createdDate": { + "type": "string" + }, + "deviceAddress": { + "type": "string" + }, + "deviceConfig": { + "type": "object" + }, + "deviceName": { + "type": "string" + }, + "deviceType": { + "type": "string" + }, + "groupRef": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/AssetTag" + } + }, + "updateDate": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "userId": { + "type": "string" + } + } + }, + "EdgeDatasource": { + "type": "object", + "properties": { + "controllerUri": { + "type": "string" + }, + "nodeName": { + "type": "string" + } + } + } + } +} diff --git a/images/javadoc.png b/images/javadoc.png new file mode 100644 index 0000000000000000000000000000000000000000..e0afa179e2bfd2d164157f5e5ce92a228a8b2eb9 GIT binary patch literal 6430 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 literal 0 HcmV?d00001 diff --git a/images/pages.jpg b/images/pages.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b93b7a82c28a3f218334de6a5572d1da0ee90ac4 GIT binary patch literal 4203 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 WLT?s8&-}~v`hSku|9UETH1QAIM{Owp literal 0 HcmV?d00001 diff --git a/manifest.yml b/manifest.yml new file mode 100644 index 0000000..6f4604f --- /dev/null +++ b/manifest.yml @@ -0,0 +1,26 @@ +--- +applications: + - name: {your-name}-kit-service + buildpack: java_buildpack + path: target/kit-service-1.0.0.jar + memory: 512M + timeout : 180 +services: + - {uaaService} + - {timeSeriesService} + - {assetService} +env: + SPRING_PROFILES_ACTIVE : cloud,asset + predix_uaa_name: {uaaService} + predix_asset_name: {assetService} + predix_timeseries_name : {timeSeriesService} + predix_oauth_clientId : {clientId}:{secret} + accessTokenEndpointUrl : https://{oauthRestHost}/oauth/token + registration_deactivation : 60 + KIT_CLOUD_APP_URL : {kitCloudUrl} + JAVA_DOCS_URL : https://predixdev.github.io/kit-service + kit_device_credentials : {deviceEncodedClient} + #logging - see application-cloud.properties + logging_level_root: INFO + logging_level_org_springframework: INFO + logging_level_com_ge_predix_solsvc: DEBUG diff --git a/manifest.yml.template b/manifest.yml.template new file mode 100644 index 0000000..e632be1 --- /dev/null +++ b/manifest.yml.template @@ -0,0 +1,22 @@ +--- +applications: + - name: {your-name}-kit-service + buildpack: java_buildpack + path: target/kit-service-1.0.0.jar + memory: 512M + timeout : 180 +services: + - {uaaService} + - {timeSeriesService} + - {assetService} +env: + SPRING_PROFILES_ACTIVE : cloud,asset + predix_uaa_name: {uaaService} + predix_asset_name: {assetService} + predix_timeseries_name : {timeSeriesService} + predix_oauth_clientId : {clientId}:{secret} + accessTokenEndpointUrl : https://{oauthRestHost}/oauth/token + registration_deactivation : 60 + KIT_CLOUD_APP_URL : {kitCloudUrl} + JAVA_DOCS_URL : https://predixdev.github.io/kit-service + kit_device_credentials : {deviceEncodedClient} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2a965fb --- /dev/null +++ b/pom.xml @@ -0,0 +1,343 @@ + + + 4.0.0 + + com.ge.predix.solsvc + kit-service + 1.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 1.2.3.RELEASE + + + + + 8.1.7.v20120910 + 1.9.2 + 4.5.2 + 1.8 + 1.1.1.RELEASE + + 2.3.1 + 2.12 + 2.10.4 + 0.7.2.201409121644 + 2.5.0 + 3.2.2 + 2.0.20 + 2.1.20 + 1.1.3 + 2.3.5 + 4.5.2 + 2.9.9 + 2.5.0 + 2.10 + + + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.cloud + spring-cloud-localconfig-connector + + + org.springframework.cloud + spring-cloud-cloudfoundry-connector + + + log4j-over-slf4j + org.slf4j + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-security + + + + org.springframework.security.oauth + spring-security-oauth2 + 2.0.12.RELEASE + + + org.springframework.security + spring-security-jwt + + + com.ge.predix + uaa-token-lib + ${uaa-lib.version} + + + org.slf4j + slf4j-log4j12 + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + com.ge.predix.solsvc + fdh-asset-handler + ${fdh-asset-handler.version} + + + com.ge.predix.solsvc + timeseries-bootstrap + ${timeseries-bootstrap.version} + + + + + logback-classic + ch.qos.logback + + + org.codehaus.groovy + groovy + ${groovy.version} + + + + + joda-time + joda-time + ${joda-time.version} + + + + io.springfox + springfox-swagger2 + ${springfox.version} + + + + io.springfox + springfox-swagger-ui + ${springfox.version} + + + + + + + org.eclipse.jetty + jetty-server + ${jetty.version} + + + org.eclipse.jetty + jetty-http + ${jetty.version} + + + org.eclipse.jetty + jetty-continuation + ${jetty.version} + + + org.eclipse.jetty + jetty-io + ${jetty.version} + + + org.eclipse.jetty + jetty-util + ${jetty.version} + + + org.eclipse.jetty + jetty-security + ${jetty.version} + + + + + + + + + org.codehaus.mojo + versions-maven-plugin + 2.2 + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + true + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + + + run-tests + integration-test + + integration-test + verify + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.version} + + + + pre-unit-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + + + com/ge/predix/solsvc/boot/Application.class + com/ge/predix/solsvc/boot/PredixBootSecurityConfig.class + + + + + + post-unit-test + test + + report + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + + ${project.reporting.outputDirectory}/jacoco-ut + + + + pre-integration-test + pre-integration-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco-it.exec + + + + + + post-integration-test + post-integration-test + + report + + + + ${project.build.directory}/coverage-reports/jacoco-it.exec + + ${project.reporting.outputDirectory}/jacoco-it + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven-javadoc-plugin.version} + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + true + ${project.build.directory} + + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.jacoco + + jacoco-maven-plugin + + + [0.7.2.201409121644,) + + + prepare-agent + + + + + + + + + + + + + + + diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/Application.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/Application.java new file mode 100644 index 0000000..557fe2d --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/Application.java @@ -0,0 +1,287 @@ +package com.ge.predix.solsvc.kitservice.boot; + +import static com.google.common.base.Predicates.or; +import static springfox.documentation.builders.PathSelectors.regex; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration; +import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.context.embedded.FilterRegistrationBean; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.ImportResource; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.context.support.StandardServletEnvironment; +import org.springframework.web.servlet.ModelAndView; + +import com.google.common.base.Predicate; + +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.ApiInfo; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger.web.UiConfiguration; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * + * @author 212421693 - + */ +@SpringBootApplication +@EnableSwagger2 +@Configuration +@EnableAutoConfiguration(exclude = +{ + DataSourceAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class, + PersistenceExceptionTranslationAutoConfiguration.class +}) +@ComponentScan(basePackages = {"com.ge.predix.solsvc.kitservice"}) +@ImportResource( +{ + "classpath*:META-INF/application-security.xml", + "classpath*:META-INF/spring/predix-rest-client-scan-context.xml", + "classpath*:META-INF/spring/ext-util-scan-context.xml", + "classpath*:META-INF/spring/fdh-asset-handler-scan-context.xml", + "classpath*:META-INF/spring/timeseries-bootstrap-scan-context.xml" + }) +@Controller +public class Application +{ + private static final Logger log = LoggerFactory.getLogger(Application.class); + @SuppressWarnings("unused") + private static ApplicationContext context; + + static String[] profiles ; + + @SuppressWarnings("javadoc") + @Value("${java.docs.url:null}") + String docsUrl ; + + /** + * @param args + * - + */ + @SuppressWarnings({}) + public static void main(String[] args) + { + SpringApplication springApplication = new SpringApplication(Application.class); + ApplicationContext ctx = springApplication.run(args); + context = ctx; + log.debug("Let's inspect the beans provided by Spring Boot:"); //$NON-NLS-1$ + String[] beanNames = ctx.getBeanDefinitionNames(); + Arrays.sort(beanNames); + for (String beanName : beanNames) + { + log.debug(beanName); + } + + log.debug("Let's inspect the profiles provided by Spring Boot:"); //$NON-NLS-1$ + profiles = ctx.getEnvironment().getActiveProfiles(); + for (int i = 0; i < profiles.length; i++) + log.debug("profile****=" + profiles[i]); //$NON-NLS-1$ + + log.info("Let's inspect the properties provided by Spring Boot:"); //$NON-NLS-1$ + MutablePropertySources propertySources = ((StandardServletEnvironment) ctx.getEnvironment()) + .getPropertySources(); + Iterator> iterator = propertySources.iterator(); + while (iterator.hasNext()) + { + Object propertySourceObject = iterator.next(); + if ( propertySourceObject instanceof org.springframework.core.env.PropertySource ) + { + org.springframework.core.env.PropertySource propertySource = (org.springframework.core.env.PropertySource) propertySourceObject; + log.info("propertySource=" + propertySource.getName() + " values=" + propertySource.getSource() //$NON-NLS-1$ //$NON-NLS-2$ + + "class=" + propertySource.getClass()); //$NON-NLS-1$ + } + } + } + + + + /** + * @param filter - + * @return - + */ + @Bean + public FilterRegistrationBean registration(AuthenticationFilter filter) + { + FilterRegistrationBean registration = new FilterRegistrationBean(filter); + registration.setEnabled(false); + return registration; + } + + /** + * @param filter - + * @return - + */ + @Bean + public FilterRegistrationBean registration2(OAuth2AuthenticationProcessingFilter filter) + { + FilterRegistrationBean registration = new FilterRegistrationBean(filter); + registration.setEnabled(false); + return registration; + } + + /** + * @return - + */ + @Bean + public Docket documentation() + { + return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.any()).paths(paths()) + .build().pathMapping("/") //$NON-NLS-1$ + .apiInfo(metadata()); + } + + /** + * + * @return - + */ + + @SuppressWarnings("unchecked") + private Predicate paths() + { + return or( + regex("/device.*")); //$NON-NLS-1$ + + } + + /** + * @return - + */ + @Bean + UiConfiguration uiConfig() + { + return new UiConfiguration("validatorUrl", // url //$NON-NLS-1$ + "none", // docExpansion => none | list //$NON-NLS-1$ + "alpha", // apiSorter => alpha //$NON-NLS-1$ + "schema", // defaultModelRendering => schema //$NON-NLS-1$ + UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, true, // enableJsonEditor + // => + // true + // | + // false + true); // showRequestHeaders => true | false + } + + /** + * Ensure the Tomcat container comes up, not the Jetty one. + * + * @return - the factory + */ + @Bean + public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() + { + return new TomcatEmbeddedServletContainerFactory(); + } + + private ApiInfo metadata() + { + return new ApiInfoBuilder().title("Kit Service") //$NON-NLS-1$ + .description("Kit Service") //$NON-NLS-1$ + .version("1.1.6") //$NON-NLS-1$ + .build(); + } + + /** + * @param request - + * @param name - + * @param model - + * @return - + */ + @RequestMapping("/") + public String greetings(HttpServletRequest request ,@RequestParam(value = "name", required = false, defaultValue = "Predix") String name, + Model model) + { StringBuffer requesturi = request.getRequestURL(); + String applicationURl = requesturi.toString().replaceAll("http", "https");//$NON-NLS-1$ //$NON-NLS-2$ + if(checkProfile("local")) { //$NON-NLS-1$ + applicationURl = requesturi.toString(); + } + + model.addAttribute("api",applicationURl.toString()+"api");//$NON-NLS-1$ //$NON-NLS-2$ + model.addAttribute("health",applicationURl.toString()+"health");//$NON-NLS-1$ //$NON-NLS-2$ + model.addAttribute("docs",this.docsUrl);//$NON-NLS-1$ + return "index"; //$NON-NLS-1$ + } + + /** + * @param profile - local + * @return - + */ + private boolean checkProfile(String profile) + { + return Arrays.asList(profiles).contains(profile); + } + + + + /** + * + * @param request + * - HttpServletRequest + * @param response + * - HttpServletResponse + * @return - Model View + * @throws Exception + * - Exception + */ + @RequestMapping("/docs") + protected ModelAndView docs(HttpServletRequest request, HttpServletResponse response) + throws Exception + { + return new ModelAndView("redirect:/javadoc/index.html"); //$NON-NLS-1$ + + } + + + /** + * @param request - + * @param response - + * @throws IOException - + */ + @RequestMapping("/api") + public @ResponseBody void api(HttpServletRequest request ,HttpServletResponse response ) throws IOException + { String applicationURl = getApplicationUrl(request); + response.sendRedirect(applicationURl.replace("/api", "/swagger-ui.html")); //$NON-NLS-1$//$NON-NLS-2$ + + } + + /** + * + * @param request + * @return - Application URL + */ + private String getApplicationUrl (final HttpServletRequest request){ + + String applicationURl = request.getRequestURL().toString().replaceAll("http", "https");//$NON-NLS-1$ //$NON-NLS-2$ + if(checkProfile("local")) { //$NON-NLS-1$ + applicationURl = request.getRequestURL().toString(); // localhost support for http + } + return applicationURl; + } + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/AuthenticationFilter.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/AuthenticationFilter.java new file mode 100644 index 0000000..99e0f45 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/AuthenticationFilter.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.boot; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.collections.CollectionUtils; +import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.jwt.Jwt; +import org.springframework.security.jwt.JwtHelper; +import org.springframework.util.StringUtils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.ge.predix.uaa.token.lib.JsonUtils; + +/** + * + * @author 212421693 - + */ +public class AuthenticationFilter + implements Filter +{ + private String tokenScope = "application-read"; //$NON-NLS-1$ + + /** + * @return the tokenScope + */ + public String getTokenScope() + { + return this.tokenScope; + } + + /** + * @param tokenScope the tokenScope to set + */ + public void setTokenScope(String tokenScope) + { + this.tokenScope = tokenScope; + } + + private static final String SECURITY_TOKEN_HEADER = "Authorization"; //$NON-NLS-1$ + private static final String authorizationSchema = "Bearer"; //$NON-NLS-1$ + + /* + * (non-Javadoc) + * @see javax.servlet.Filter#destroy() + */ + @Override + public void destroy() + { + // TODO Auto-generated method stub + + } + + /* + * (non-Javadoc) + * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) + */ + @Override + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) + throws IOException, ServletException + { + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + String stringToken = request.getHeader(SECURITY_TOKEN_HEADER); + + if ( StringUtils.isEmpty(stringToken) ) + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + throw new InsufficientAuthenticationException("Authorization header not found"); //$NON-NLS-1$ + } + + if ( !StringUtils.startsWithIgnoreCase(stringToken, authorizationSchema) ) + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + throw new InsufficientAuthenticationException("Authorization schema " + authorizationSchema + " not found"); //$NON-NLS-1$ //$NON-NLS-2$ + } + + stringToken = stringToken.trim().substring(authorizationSchema.length()); + + Jwt accessToken = JwtHelper.decode(stringToken); + Map claims = JsonUtils.readValue(accessToken.getClaims(), + new TypeReference>() + {// + }); + if ( claims == null ) + { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + throw new InsufficientAuthenticationException( + "Authorization header does not have the required scope to access the resource claims are not set"); //$NON-NLS-1$ + } + Set scopes = new HashSet<>(); + if ( claims.containsKey("scope") ) //$NON-NLS-1$ + { + @SuppressWarnings("unchecked") + Collection values = (Collection) claims.get("scope");//$NON-NLS-1$ + scopes.addAll(values); + } + // check for the right scope + Boolean foundScope = Boolean.FALSE; + for (String scope : scopes) + { + if ( org.apache.commons.lang.StringUtils.equalsIgnoreCase(scope, this.tokenScope) ) + { + foundScope = Boolean.TRUE; + } + + } + request.setAttribute("userToken", accessToken); //$NON-NLS-1$ + + if ( !foundScope ) + { + + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + throw new InsufficientAuthenticationException( + "Authorization header does not have the required scope to access the resource"); //$NON-NLS-1$ + } + // setting security Context + + chain.doFilter(req, res); + + } + + /* + * (non-Javadoc) + * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) + */ + @Override + public void init(FilterConfig arg0) + throws ServletException + { + // TODO Auto-generated method stub + + } + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/ErrorResponseController.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/ErrorResponseController.java new file mode 100644 index 0000000..6b3911a --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/ErrorResponseController.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.boot; + +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.web.ErrorAttributes; +import org.springframework.boot.autoconfigure.web.ErrorController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.ServletRequestAttributes; + +/** + * + * @author 212421693 - + */ +@RestController +public class ErrorResponseController + implements ErrorController +{ + private static final String PATH = "/error"; //$NON-NLS-1$ + + @Value("${debug:false}") + private boolean debug; + + @Autowired + private ErrorAttributes errorAttributes; + + /** + * @param request - + * @param response - + * @return - + */ + @RequestMapping(value = PATH) + EventError error(HttpServletRequest request, HttpServletResponse response) + { + // Appropriate HTTP response code (e.g. 404 or 500) is automatically set by Spring. + // Here we just define response body. + return new EventError(response.getStatus(), getErrorAttributes(request, this.debug)); + } + + @Override + public String getErrorPath() + { + return PATH; + } + + private Map getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) + { + RequestAttributes requestAttributes = new ServletRequestAttributes(request); + return this.errorAttributes.getErrorAttributes(requestAttributes, includeStackTrace); + } +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/EventError.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/EventError.java new file mode 100644 index 0000000..2e9c6ea --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/EventError.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.boot; + +import java.util.Map; + +import org.springframework.util.StringUtils; + + + +/** + * + * @author 212421693 - + */ +public class EventError +{ + /** + * status + */ + Integer status; + /** + * error + */ + String error; + + /** + * message + */ + String message; + /** + * timeStamp + */ + String timeStamp; + + /** + * @param status + * - + * @param errorAttributes + * - + */ + public EventError(int status, Map errorAttributes) + { + this.status = status; + this.error = (String) errorAttributes.get("error"); //$NON-NLS-1$ + this.message = (String) errorAttributes.get("message"); //$NON-NLS-1$ + if(! StringUtils.isEmpty(errorAttributes.get("timestamp"))) {//$NON-NLS-1$ + this.timeStamp = errorAttributes.get("timestamp").toString(); //$NON-NLS-1$ + } + + } + + /** + * @return the status + */ + public Integer getStatus() + { + return this.status; + } + + /** + * @param status the status to set + */ + public void setStatus(Integer status) + { + this.status = status; + } + + /** + * @return the error + */ + public String getError() + { + return this.error; + } + + /** + * @param error the error to set + */ + public void setError(String error) + { + this.error = error; + } + + /** + * @return the message + */ + public String getMessage() + { + return this.message; + } + + /** + * @param message the message to set + */ + public void setMessage(String message) + { + this.message = message; + } + + /** + * @return the timeStamp + */ + public String getTimeStamp() + { + return this.timeStamp; + } + + /** + * @param timeStamp the timeStamp to set + */ + public void setTimeStamp(String timeStamp) + { + this.timeStamp = timeStamp; + } + + + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/SwaggerConfiguration.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/SwaggerConfiguration.java new file mode 100644 index 0000000..5ab6226 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/SwaggerConfiguration.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.boot; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +/** + * + * @author 212421693 - + */ +@Configuration +public class SwaggerConfiguration extends WebMvcConfigurerAdapter +{ + @Override + public void addViewControllers(ViewControllerRegistry registry) + { + registry.addRedirectViewController("/api/v2/api-docs", "/v2/api-docs"); //$NON-NLS-1$ //$NON-NLS-2$ + registry.addRedirectViewController("/api/configuration/ui", "/configuration/ui"); //$NON-NLS-1$ //$NON-NLS-2$ + registry.addRedirectViewController("/api/configuration/security", "/configuration/security"); //$NON-NLS-1$ //$NON-NLS-2$ + registry.addRedirectViewController("/api/swagger-resources", "/swagger-resources"); //$NON-NLS-1$ //$NON-NLS-2$ + + } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) + { + registry.addResourceHandler("/api/**").addResourceLocations("classpath:/META-INF/resources/"); //$NON-NLS-1$ //$NON-NLS-2$ + } +} \ No newline at end of file diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/boot/utils/FdhUtils.java b/src/main/java/com/ge/predix/solsvc/kitservice/boot/utils/FdhUtils.java new file mode 100644 index 0000000..6f5a189 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/boot/utils/FdhUtils.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.boot.utils; + +import org.apache.commons.lang3.StringUtils; + +import com.ge.predix.entity.assetfilter.AssetFilter; +import com.ge.predix.entity.field.Field; +import com.ge.predix.entity.field.fieldidentifier.FieldIdentifier; +import com.ge.predix.entity.fielddata.FieldData; +import com.ge.predix.entity.fielddata.PredixString; +import com.ge.predix.entity.fielddatacriteria.FieldDataCriteria; +import com.ge.predix.entity.fieldselection.FieldSelection; +import com.ge.predix.entity.getfielddata.GetFieldDataRequest; +import com.ge.predix.entity.putfielddata.PutFieldDataCriteria; +import com.ge.predix.entity.putfielddata.PutFieldDataRequest; + +/** + * + * @author 212421693 - + */ +public class FdhUtils +{ + + + /** + * + * @param device - + * @param group - + * @param userGroup - + * @return - + */ + public static PutFieldDataRequest createRegisterPutRequest(String device, String group, String userGroup) + { + + + // Request + PutFieldDataRequest putFieldDataRequest = new PutFieldDataRequest(); + putFieldDataRequest.setCorrelationId("string"); //$NON-NLS-1$ + putFieldDataRequest.getPutFieldDataCriteria().add( getFieldCriteria(device)); + if(StringUtils.isNotEmpty(group)) + putFieldDataRequest.getPutFieldDataCriteria().add( getFieldCriteria(group)); + if(StringUtils.isNotEmpty(userGroup)) + putFieldDataRequest.getPutFieldDataCriteria().add( getFieldCriteria(userGroup)); + + return putFieldDataRequest; + } + + + /** + * @param device + * @return - + */ + private static PutFieldDataCriteria getFieldCriteria(String dataString) + { + FieldData fieldData = new FieldData(); + Field field = new Field(); + FieldIdentifier fieldIdentifier = new FieldIdentifier(); + field.setFieldIdentifier(fieldIdentifier); + fieldData.getField().add(field); + + //device + PredixString data = new PredixString(); + data.setString(dataString); + fieldData.setData(data); + + // Criteria + PutFieldDataCriteria fieldDataCriteria = new PutFieldDataCriteria(); + fieldDataCriteria.setFieldData(fieldData); + return fieldDataCriteria; + } + + + /** + * @param filterFieldValue - + * @param expectedDataType - + * @param deviceIdentifier - + * @param string - + * @param userId - + * @param deviceAddress - + * @return - + */ + public static GetFieldDataRequest createGetUserDeviceRequest(String filterFieldValue, String expectedDataType, String userId, + String deviceAddress) + { + GetFieldDataRequest getFieldDataRequest = new GetFieldDataRequest(); + + FieldDataCriteria fieldDataCriteria = new FieldDataCriteria(); + + // SELECT + FieldSelection fieldSelection = new FieldSelection(); + FieldIdentifier fieldIdentifier = new FieldIdentifier(); + fieldIdentifier.setId("/PredixString"); //$NON-NLS-1$ default needed by the system + fieldSelection.setFieldIdentifier(fieldIdentifier); + fieldSelection.setExpectedDataType(expectedDataType); + + // FILTER + AssetFilter assetFilter = new AssetFilter(); + assetFilter.setUri(filterFieldValue); + + if(StringUtils.isEmpty(userId) && !StringUtils.isEmpty(deviceAddress)) { + assetFilter.setFilterString("deviceAddress="+deviceAddress); //$NON-NLS-1$ + } + else if(StringUtils.isEmpty(deviceAddress)) { + assetFilter.setFilterString("userId="+userId); //$NON-NLS-1$ + } else { + assetFilter.setFilterString("userId="+userId+":deviceAddress="+deviceAddress); //$NON-NLS-1$ //$NON-NLS-2$ + } + + // SELECT + fieldDataCriteria.getFieldSelection().add(fieldSelection); + // WHERE + fieldDataCriteria.setFilter(assetFilter); + + getFieldDataRequest.getFieldDataCriteria().add(fieldDataCriteria); + return getFieldDataRequest; + } + + /** + * + * @param groupRef - + * @param expectedDataType - + * @param userId - + * @return - + */ + public static GetFieldDataRequest createGetGroupRequest(String groupRef, String expectedDataType) + { + GetFieldDataRequest getFieldDataRequest = new GetFieldDataRequest(); + + FieldDataCriteria fieldDataCriteria = new FieldDataCriteria(); + + // SELECT + FieldSelection fieldSelection = new FieldSelection(); + FieldIdentifier fieldIdentifier = new FieldIdentifier(); + fieldIdentifier.setId("/PredixString"); //$NON-NLS-1$ default needed by the system + fieldSelection.setFieldIdentifier(fieldIdentifier); + fieldSelection.setExpectedDataType(expectedDataType); + + // FILTER + AssetFilter assetFilter = new AssetFilter(); + assetFilter.setUri(groupRef); + + // SELECT + fieldDataCriteria.getFieldSelection().add(fieldSelection); + // WHERE + fieldDataCriteria.setFilter(assetFilter); + + getFieldDataRequest.getFieldDataCriteria().add(fieldDataCriteria); + return getFieldDataRequest; + } + + +/** + * @param userGroupRef - + * @param groupRef - + * @param expectedDataType - + * @param userId - + * @return - + */ +public static GetFieldDataRequest createGetUserGroupRequest(String userGroupRef, String expectedDataType, String userId) +{ + GetFieldDataRequest getFieldDataRequest = new GetFieldDataRequest(); + + FieldDataCriteria fieldDataCriteria = new FieldDataCriteria(); + + // SELECT + FieldSelection fieldSelection = new FieldSelection(); + FieldIdentifier fieldIdentifier = new FieldIdentifier(); + fieldIdentifier.setId("/PredixString"); //$NON-NLS-1$ default needed by the system + fieldSelection.setFieldIdentifier(fieldIdentifier); + fieldSelection.setExpectedDataType(expectedDataType); + + // FILTER + AssetFilter assetFilter = new AssetFilter(); + assetFilter.setUri(userGroupRef); + assetFilter.setFilterString("users="+userId); //$NON-NLS-1$ + + // SELECT + fieldDataCriteria.getFieldSelection().add(fieldSelection); + // WHERE + fieldDataCriteria.setFilter(assetFilter); + + getFieldDataRequest.getFieldDataCriteria().add(fieldDataCriteria); + return getFieldDataRequest; +} +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/controller/HelloController.java b/src/main/java/com/ge/predix/solsvc/kitservice/controller/HelloController.java new file mode 100644 index 0000000..7f2c0d9 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/controller/HelloController.java @@ -0,0 +1,53 @@ +package com.ge.predix.solsvc.kitservice.controller; + +import java.util.Date; + +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * An example of creating a Rest api using Spring Annotations @RestController. + * + * + * + * @author predix + */ +@RestController +public class HelloController +{ + + /** + * + */ + public HelloController() + { + super(); + } + + /** + * Sample Endpoint which returns a Welcome Message + * + * @param echo + * - the string to echo back + * @return - + */ + @SuppressWarnings("nls") + @RequestMapping(value = "/echo", method = RequestMethod.GET) + public String index(@RequestParam(value = "echo", defaultValue = "echo this text") String echo) + { + return "Greetings from Predix Spring Boot! echo=" + echo + " " + (new Date()); + } + + /** + * @return - + */ + @SuppressWarnings("nls") + @RequestMapping(value = "/health", method = RequestMethod.GET) + public String health() + { + return String.format("{\"status\":\"up\", \"date\": \" " + new Date() + "\"}"); + } + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/controller/KitController.java b/src/main/java/com/ge/predix/solsvc/kitservice/controller/KitController.java new file mode 100644 index 0000000..a35a9bd --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/controller/KitController.java @@ -0,0 +1,362 @@ +package com.ge.predix.solsvc.kitservice.controller; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.jwt.Jwt; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.validation.ValidationUtils; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.ge.predix.solsvc.kitservice.boot.EventError; +import com.ge.predix.solsvc.kitservice.error.DeviceRegistrationError; +import com.ge.predix.solsvc.kitservice.manager.DeviceManager; +import com.ge.predix.solsvc.kitservice.model.RegisterDevice; +import com.ge.predix.solsvc.kitservice.validator.RegisterDeviceValidation; +import com.ge.predix.uaa.token.lib.JsonUtils; + +/** + * Rest API controller for registration of kits + * + * + * + * @author predix + */ +@RestController() +public class KitController +{ + + private static final Logger log = LoggerFactory.getLogger(KitController.class); + + @Autowired + private DeviceManager deviceManager; + + /** + * + */ + public KitController() + { + super(); + } + + /** + * Sample End point which returns a Welcome Message + * + * @param request - + * + * @param echo + * - the string to echo back + * @return - + */ + @RequestMapping(value = "/device", method = RequestMethod.GET) + public ResponseEntity> getDevices(HttpServletRequest request,@SuppressWarnings({ + "javadoc", "unused" + }) @RequestHeader("Authorization") String authorization) + { + String userId = getUserId(request); + List devices = this.getDeviceManager().getDevices(userId); + return new ResponseEntity>(devices, HttpStatus.OK); + } + + /** + * Method that registers a device + * + * @param device - + * @param request - + * @param result - + * @return - + */ + @SuppressWarnings("unused") + @RequestMapping(value = "/device/register", method = RequestMethod.POST) + public ResponseEntity registerDevice(@RequestBody RegisterDevice device, HttpServletRequest request, + BindingResult result,@SuppressWarnings("javadoc") @RequestHeader("Authorization") String authorization) + { + String userId = getUserId(request); + log.info("Calling registerKit for user " + userId); //$NON-NLS-1$ + device.setUserId(userId); + + // validation + RegisterDeviceValidation validation = new RegisterDeviceValidation(); + validation.validate(device, result); + if ( result.hasErrors() ) + { + List errors = setErrors(result.getFieldErrors(), HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); + } + // continue to register device + RegisterDevice originalDevice = this.getDeviceManager().getDevice("device", userId, device.getDeviceAddress());//$NON-NLS-1$ + try + { + if ( originalDevice == null ) + { + // device not found. register it. + log.info("Registrating device with address " + device.getDeviceAddress()); //$NON-NLS-1$ + this.getDeviceManager().registerDevice(device); + } + else + { + device = originalDevice; + // check device expiry + this.getDeviceManager().checkDeviceExpiry(originalDevice); + } + } + catch (DeviceRegistrationError e) + { + List errors = setErrors(e, HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); + } + // setting config + device.setDeviceConfig(this.getDeviceManager().getDeviceConfig()); + return new ResponseEntity(device, HttpStatus.OK); + } + + /** + * - + * + * @param list + * @param status + */ + private List setErrors(List errors, int status) + { + List eventErrors = new ArrayList(); + + if ( CollectionUtils.isNotEmpty(errors) ) + { + for (FieldError error : errors) + { + Map errorAttributes = new HashMap(); + errorAttributes.put("error", error.getField()); //$NON-NLS-1$ + errorAttributes.put("message", error.getField() + "reject for value "+error.getRejectedValue() + error.getDefaultMessage());//$NON-NLS-1$ //$NON-NLS-2$ + EventError eventError = new EventError(status, errorAttributes); + eventErrors.add(eventError); + + } + } + return eventErrors; + + } + + /** + * @param allErrors + * @param value + * @return - + */ + private List setObjectErrors(List errors, int status) + { + List eventErrors = new ArrayList(); + if ( CollectionUtils.isNotEmpty(errors) ) + { + for (ObjectError error : errors) + { + Map errorAttributes = new HashMap(); + errorAttributes.put("error", error.getObjectName()); //$NON-NLS-1$ + errorAttributes.put("message", error.getDefaultMessage());//$NON-NLS-1$ //$NON-NLS-2$ + EventError eventError = new EventError(status, errorAttributes); + eventErrors.add(eventError); + + } + } + return eventErrors; + } + + /** + * Method that updated the device + * @param deviceId - + * + * @param device - + * @param request - + * @param result - + * @param authorization - + * @return - + */ + + @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.PUT) + public ResponseEntity updateRegisterDevice(@PathVariable String deviceId,@RequestBody RegisterDevice device, HttpServletRequest request, + BindingResult result, @RequestHeader("Authorization") String authorization) + { + String userId = getUserId(request); + log.info("Calling registerKit for user " + userId); //$NON-NLS-1$ + + List errors = new ArrayList(); + if(!RegisterDeviceValidation.validate(deviceId, Pattern.compile(RegisterDeviceValidation.DEVICE_NAME_PATTERN))) { //$NON-NLS-1$ + ObjectError error = new ObjectError("deviceId", "Device id should match ^[A-Za-z0-9-]*"); //$NON-NLS-1$//$NON-NLS-2$ + errors.add(error); + } + + if( RegisterDeviceValidation.DEVICE_ADDRESS_LENGTH <= deviceId.length()){ + ObjectError error = new ObjectError("deviceId", "DeviceId is limited to max 75"); //$NON-NLS-1$//$NON-NLS-2$ + errors.add(error); + } + + if ( CollectionUtils.isNotEmpty(errors)) + { + List eventErrors = setObjectErrors(errors, HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + } + device.setUserId(userId); + device.setDeviceAddress(deviceId); + + + RegisterDeviceValidation validation = new RegisterDeviceValidation(); + validation.validate(device, result); + if ( result.hasErrors() ) + { + List eventErrors = setErrors(result.getFieldErrors(), HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + } + // check if the device exists + RegisterDevice originalDevice = this.getDeviceManager().getDevice("device", userId, device.getDeviceAddress());//$NON-NLS-1$ + if ( originalDevice == null ) + { + // device not found. + log.info("device not found for the user " + device.getDeviceAddress()); //$NON-NLS-1$ + ObjectError error = new ObjectError("deviceAddress", "Device with not registerted"); //$NON-NLS-1$//$NON-NLS-2$ + result.addError(error); + List eventErrors = setErrors(result.getFieldErrors(), HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + + } + try + { + this.getDeviceManager().updateDevice(device, originalDevice); + + } + catch (DeviceRegistrationError e) + { + List eventErrors = setErrors(e, HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + } + return this.getDevice(deviceId, request, authorization); + + } + + /** + * @param e + * @param badRequest + * @return - + */ + private List setErrors(DeviceRegistrationError e, int status) + { + List eventErrors = new ArrayList(); + Map errorAttributes = new HashMap(); + errorAttributes.put("error", e.getMessage()); //$NON-NLS-1$ + errorAttributes.put("message", e.getMessage());//$NON-NLS-1$ + EventError eventError = new EventError(status, errorAttributes); + eventErrors.add(eventError); + + return eventErrors; + } + + + /** + * @param request + * @return - + */ + private String getUserId(HttpServletRequest request) + { + Jwt accessToken = (Jwt) request.getAttribute("userToken"); //$NON-NLS-1$ + if ( accessToken == null ) return null; + Map claims = JsonUtils.readValue(accessToken.getClaims(), + new TypeReference>() + {// + }); + if ( claims == null ) return null; + return (String) claims.get("user_id"); //$NON-NLS-1$ + } + + /** + * Details about each Device + * + * @param deviceId - + * @param model - + * @param request - + * @param authorization - + * @param result - + * @param echo - + * @return - + */ + @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) + public ResponseEntity getDevice(@PathVariable String deviceId, HttpServletRequest request, + @RequestHeader("Authorization") String authorization) + { + String userId = getUserId(request); + + List errors = new ArrayList(); + if(!RegisterDeviceValidation.validate(deviceId, Pattern.compile(RegisterDeviceValidation.DEVICE_NAME_PATTERN))) { //$NON-NLS-1$ + ObjectError error = new ObjectError("deviceId", "Device id should match ^[A-Za-z0-9-]*"); //$NON-NLS-1$//$NON-NLS-2$ + errors.add(error); + } + + if( RegisterDeviceValidation.DEVICE_ADDRESS_LENGTH <= deviceId.length()){ + ObjectError error = new ObjectError("deviceId", "DeviceId is limited to max 75"); //$NON-NLS-1$//$NON-NLS-2$ + errors.add(error); + } + + if ( CollectionUtils.isNotEmpty(errors)) + { + List eventErrors = setObjectErrors(errors, HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + } + // continue with get + + RegisterDevice device = this.getDeviceManager().getDevice(deviceId, userId); + + if ( device == null ) + { + return new ResponseEntity<>(device, HttpStatus.NOT_FOUND); + } + // check device activation + try + { + this.getDeviceManager().checkDeviceExpiry(device); + } + catch (DeviceRegistrationError e) + { + List eventErrors = setErrors(e, HttpStatus.BAD_REQUEST.value()); + return new ResponseEntity<>(eventErrors, HttpStatus.BAD_REQUEST); + } + device.setDeviceConfig(this.getDeviceManager().getDeviceConfig()); + return new ResponseEntity(device, HttpStatus.OK); + } + + + + /** + * @return the deviceManager + */ + public DeviceManager getDeviceManager() + { + return this.deviceManager; + } + + /** + * @param deviceManager the deviceManager to set + */ + public void setDeviceManager(DeviceManager deviceManager) + { + this.deviceManager = deviceManager; + } + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/error/DeviceRegistrationError.java b/src/main/java/com/ge/predix/solsvc/kitservice/error/DeviceRegistrationError.java new file mode 100644 index 0000000..6bd815a --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/error/DeviceRegistrationError.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.error; + +/** + * + * @author 212421693 - + */ + +public class DeviceRegistrationError extends Exception +{ + + /** + * + */ + private static final long serialVersionUID = 1L; + + /** + * - + */ + public DeviceRegistrationError() + { + // TODO Auto-generated constructor stub + } + + /** + * @param message - + * @param cause - + * @param enableSuppression - + * @param writableStackTrace - + */ + public DeviceRegistrationError(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) + { + super(message, cause, enableSuppression, writableStackTrace); + // TODO Auto-generated constructor stub + } + + /** + * @param message - + * @param cause - + */ + public DeviceRegistrationError(String message, Throwable cause) + { + super(message, cause); + + } + + /** + * @param message - + */ + public DeviceRegistrationError(String message) + { + super(message); + + } + + /** + * @param cause - + */ + public DeviceRegistrationError(Throwable cause) + { + super(cause); + + } + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/manager/BaseManager.java b/src/main/java/com/ge/predix/solsvc/kitservice/manager/BaseManager.java new file mode 100644 index 0000000..f6682bd --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/manager/BaseManager.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.manager; + +import java.util.List; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.http.Header; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.ge.predix.entity.fielddata.FieldData; +import com.ge.predix.entity.getfielddata.GetFieldDataRequest; +import com.ge.predix.entity.getfielddata.GetFieldDataResult; +import com.ge.predix.solsvc.ext.util.JsonMapper; +import com.ge.predix.solsvc.fdh.handler.GetDataHandler; + +/** + * + * @author 212421693 - + */ +public abstract class BaseManager +{ + private static final Logger log = LoggerFactory.getLogger(BaseManager.class); + + /** + * + */ + @Autowired + protected JsonMapper jsonMapper; + + @Autowired + private GetDataHandler assetGetFieldDataHandler; + + + + /** + * @param request - + * @param headers - + * @return - + */ + protected List getFieldDataResult(GetFieldDataRequest request, List
headers) + { + GetFieldDataResult getResult = this.assetGetFieldDataHandler.getData(request, null, headers); + log.debug(this.jsonMapper.toJson(getResult)); + if ( !CollectionUtils.isEmpty(getResult.getErrorEvent()) ) + { + log.info("Error: fetching data"+this.jsonMapper.toJson(getResult)); //$NON-NLS-1$ + return null; + // TBD do something + } + if ( CollectionUtils.isEmpty(getResult.getFieldData()) || ( CollectionUtils.isNotEmpty(getResult.getFieldData()) && getResult.getFieldData().get(0).getData() == null) ) + { + log.info("Data Not found for "+this.jsonMapper.toJson(getResult)); //$NON-NLS-1$ + return null; + + } + return getResult.getFieldData(); + + } + + + + /** + * @return the jsonMapper + */ + public JsonMapper getJsonMapper() + { + return this.jsonMapper; + } + + + + /** + * @param jsonMapper the jsonMapper to set + */ + public void setJsonMapper(JsonMapper jsonMapper) + { + this.jsonMapper = jsonMapper; + } + + + + /** + * @return the assetGetFieldDataHandler + */ + public GetDataHandler getAssetGetFieldDataHandler() + { + return this.assetGetFieldDataHandler; + } + + + + /** + * @param assetGetFieldDataHandler the assetGetFieldDataHandler to set + */ + public void setAssetGetFieldDataHandler(GetDataHandler assetGetFieldDataHandler) + { + this.assetGetFieldDataHandler = assetGetFieldDataHandler; + } + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/manager/DeviceManager.java b/src/main/java/com/ge/predix/solsvc/kitservice/manager/DeviceManager.java new file mode 100644 index 0000000..1d58cb8 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/manager/DeviceManager.java @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.manager; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.text.StrSubstitutor; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.message.BasicHeader; +import org.joda.time.DateTime; +import org.joda.time.Days; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +import com.ge.predix.entity.asset.AssetTag; +import com.ge.predix.entity.fielddata.Data; +import com.ge.predix.entity.fielddata.FieldData; +import com.ge.predix.entity.fielddata.PredixString; +import com.ge.predix.entity.getfielddata.GetFieldDataRequest; +import com.ge.predix.entity.putfielddata.PutFieldDataRequest; +import com.ge.predix.entity.putfielddata.PutFieldDataResult; +import com.ge.predix.solsvc.fdh.handler.PutDataHandler; +import com.ge.predix.solsvc.kitservice.boot.utils.FdhUtils; +import com.ge.predix.solsvc.kitservice.error.DeviceRegistrationError; +import com.ge.predix.solsvc.kitservice.model.RegisterDevice; +import com.ge.predix.solsvc.kitservice.model.UserGroup; +import com.ge.predix.solsvc.restclient.config.IOauthRestConfig; +import com.ge.predix.solsvc.restclient.impl.RestClient; +import com.ge.predix.solsvc.timeseries.bootstrap.config.ITimeseriesConfig; + +/** + * + * @author 212421693 - + */ +@Component +public class DeviceManager extends BaseManager +{ + private static final Logger log = LoggerFactory.getLogger(DeviceManager.class); + private static final String DEVICE = "device"; //$NON-NLS-1$ + private static final String GROUP = "group"; //$NON-NLS-1$ + + + @Autowired + @Qualifier("defaultOauthRestConfig") + private IOauthRestConfig restConfig; + + @Autowired + private PutDataHandler assetPutFieldDataHandler; + + @Autowired + private RestClient restClient; + + @Autowired + private + ResourceLoader resourceLoader; + + @Autowired + @Qualifier("defaultTimeseriesConfig") + private ITimeseriesConfig timeseriesConfig; + + @Autowired + private GroupManagementService groupManagementService; + + // this number will be in days + @Value("${register.device.deactivation:#{60}}") + private String deactivationPeriod; + + @SuppressWarnings("javadoc") + @Value("${kit.webapp.url:null}") + String kitApplicationUrl; + + @SuppressWarnings("javadoc") + @Value("${kit.device.credentials:null}") + String deviceCredentials; + + + + /** + * + * @param deviceIdentifier - + * @param userId - + * @return - + */ + public RegisterDevice getDevice(String deviceIdentifier, String userId) + { + log.info("Calling getDevice"); //$NON-NLS-1$ + return getDevice("/"+DEVICE,userId, deviceIdentifier); //$NON-NLS-1$ + + } + + /** + * Registers a device + * @param device - + * @return RegisterDevice + * @throws DeviceRegistrationError - + */ + public RegisterDevice registerDevice(RegisterDevice device) throws DeviceRegistrationError + { + // reactivation TBD + log.info("Calling registerDevice for device="+device.getUri()+" User = "+device.getUserId()); //$NON-NLS-1$ //$NON-NLS-2$ + return createorUpdateDevice(device); + } + + + /** + * @param device - + * @return RegisterDevice + * @throws DeviceRegistrationError + */ + private RegisterDevice createorUpdateDevice(RegisterDevice device) throws DeviceRegistrationError + { + + List
headers = getServiceHeaders(); + log.debug("In here to get Service Headers "+this.jsonMapper.toJson(device)); + if(StringUtils.isEmpty(device.getUri())){ + device.setUri("/"+DEVICE+"/"+device.getDeviceAddress()); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if(device.getCreatedDate() == null ) { + device.setCreatedDate(String.valueOf(Instant.now().toEpochMilli())); + } + if(device.getUpdateDate() == null ) { + device.setUpdateDate(String.valueOf(Instant.now().toEpochMilli())); + } + + if(device.getActivationDate() == null ) { + device.setActivationDate(String.valueOf(Instant.now().toEpochMilli())); + } + + if(!StringUtils.isEmpty(device.getGroupRef()) && !device.getGroupRef().startsWith("/group")){ //$NON-NLS-1$ + String groupRef= device.getGroupRef(); + device.setGroupRef("/"+GROUP+"/"+groupRef); //$NON-NLS-1$ //$NON-NLS-2$ + } + + + // add default Asset tags + List tags = getDefaultTags(device.getDeviceAddress()); + device.setTags(new HashSet(tags)); + + // User and user group + UserGroup userGroup = this.groupManagementService.getOrCreateUserGroup(headers,device.getUserId()); + String userGroupString = this.groupManagementService.getUserGroupString(userGroup); + String group = this.groupManagementService.getOrCreateGroup(headers,userGroup.getUri(),device.getGroupRef()); + + log.debug("With group"+group + "userGroup" + userGroupString); //$NON-NLS-1$ //$NON-NLS-2$ + + + List kitModels = new ArrayList<>(); + kitModels.add(device); + String deviceString = this.jsonMapper.toJson(kitModels); + PutFieldDataRequest putFieldDataRequest = FdhUtils.createRegisterPutRequest(deviceString,group,userGroupString); + PutFieldDataResult result = this.assetPutFieldDataHandler.putData(putFieldDataRequest, null, headers, + HttpPost.METHOD_NAME); + log.debug(this.jsonMapper.toJson(result)); + if ( !CollectionUtils.isEmpty(result.getErrorEvent()) ) + { + log.info("Error: registering/Updating Device"); //$NON-NLS-1$ + //TBD: do something + throw new DeviceRegistrationError(result.getErrorEvent().get(0)); + } + return device; + + } + + /** + * @param data + * @return - + */ + private RegisterDevice getDeviceInfoFromData(Data predixString) + { + PredixString data = (PredixString) predixString; + String deviceString = StringEscapeUtils.unescapeJava(data.getString()); + deviceString = deviceString.substring(1, deviceString.length() - 1); + deviceString = deviceString.substring(0, deviceString.length()); + List registeredDevice = this.jsonMapper.fromJsonArray("["+deviceString+"]", RegisterDevice.class); //$NON-NLS-1$ //$NON-NLS-2$ + if(CollectionUtils.isNotEmpty(registeredDevice)) + return registeredDevice.get(0); + return null; + } + + + /** + * @return - + */ + private List getDefaultTags(String deviceAddress) + { + Map valuesMap = new HashMap(); + valuesMap.put("DEVICE_ADDRESS", deviceAddress);//$NON-NLS-1$ + StrSubstitutor sub = new StrSubstitutor(valuesMap); + String jsonTemplate = sub.replace(jsonTagTemplate()); + + //log.info("read Json is " +jsonTemplate ); //$NON-NLS-1$ + return this.jsonMapper.fromJsonArray(jsonTemplate, AssetTag.class); + + } + + /** + * TBD either cache this or use the vault service + * + * @return - + */ + private List
getServiceHeaders() + { + List
headers = this.restClient.getSecureTokenForClientId(); + headers.add(new BasicHeader("Content-Type", "application/json")); //$NON-NLS-1$//$NON-NLS-2$ + return headers; + } + + /** + * @param userId - + * @return - + */ + public List getDevices(String userId) + { + log.info("Calling get All Device for"); //$NON-NLS-1$ + return getDevice(userId); + } + + /** + * @param deviceIdentifier - + * @param userId - + * @param deviceAddress - + * @param deviceName - + * @return - + */ + public List getDevice(String userId) + { + log.info("Calling getDevice"); //$NON-NLS-1$ + List devices= new ArrayList (); + List
headers = getServiceHeaders(); + GetFieldDataRequest request = FdhUtils.createGetUserDeviceRequest("/"+DEVICE, "PredixString",userId,null); //$NON-NLS-1$ //$NON-NLS-2$ + List fieldDatas= getFieldDataResult(request,headers); + + if(CollectionUtils.isNotEmpty(fieldDatas)) { + for(FieldData fieldData:fieldDatas){ + devices.add( getDeviceInfoFromData(fieldData.getData())); + } + } + + return devices; + } + + + + /** + * @param deviceIdentifier - + * @param userId - + * @param deviceAddress - + * @param deviceName - + * @return - + */ + public RegisterDevice getDevice(String deviceIdentifier, String userId, String deviceAddress) + { + + log.info("Calling getDevice by user and device address"); //$NON-NLS-1$ + RegisterDevice device =null; + List
headers = getServiceHeaders(); + GetFieldDataRequest request = FdhUtils.createGetUserDeviceRequest(deviceIdentifier, "PredixString",userId,deviceAddress); //$NON-NLS-1$ + List fieldData = getFieldDataResult(request,headers); + if(CollectionUtils.isNotEmpty(fieldData)) { + return getDeviceInfoFromData(fieldData.get(0).getData()); + } + return device; + } + + + /** + * + * @return - + */ + private String jsonTagTemplate() { + String tagModelTemplate = null ; + try { + log.info("DeviceManager: Loading asset-model..."); //$NON-NLS-1$ + Resource resource = getResourceLoader().getResource("classpath:asset-model/device-asset-tags.json"); //$NON-NLS-1$ + File dbAsFile = resource.getFile(); + tagModelTemplate = FileUtils.readFileToString(dbAsFile, "UTF-8"); //$NON-NLS-1$ + return tagModelTemplate; + } catch (IOException | NullPointerException e) { + log.error("DeviceManager: Asset model could not be initialized. ", e); //$NON-NLS-1$ + } + return tagModelTemplate; + } + + /** + * @return the resourceLoader + */ + public ResourceLoader getResourceLoader() + { + return this.resourceLoader; + } + + /** + * @param resourceLoader the resourceLoader to set + */ + public void setResourceLoader(ResourceLoader resourceLoader) + { + this.resourceLoader = resourceLoader; + } + + /** + * + * @return - + */ + @SuppressWarnings({ + "unchecked", "nls" + }) + public Map getDeviceConfig() + { + @SuppressWarnings("rawtypes") + Map deviceConfig = new LinkedHashMap(); + deviceConfig.put("predixUaaIssuer", this.restConfig.getOauthIssuerId()); //$NON-NLS-1$ + + deviceConfig.put("client",this.deviceCredentials); + deviceConfig.put("predixTimeSeriesIngestUri", this.timeseriesConfig.getWsUri()); //$NON-NLS-1$ + deviceConfig.put("predixTimeSeriesZoneid", this.timeseriesConfig.getZoneId()); + deviceConfig.put("deviceDeactivationPeriod", this.deactivationPeriod); + deviceConfig.put("cloudApplicationUrl", this.kitApplicationUrl); + return deviceConfig; + + } + + + /** + * @param device - + * @param originalDevice - + * @throws DeviceRegistrationError - + */ + public void updateDevice(RegisterDevice device, RegisterDevice originalDevice) throws DeviceRegistrationError + { + log.info("Calling updateDevice for device="+device.getUri()+" User = "+device.getUserId()); //$NON-NLS-1$ //$NON-NLS-2$ + + if(StringUtils.isNotEmpty(device.getDeviceName()) && ! originalDevice.getDeviceName().equalsIgnoreCase(device.getDeviceName())) { + originalDevice.setDeviceName(device.getDeviceName()); + } + if(StringUtils.isNotEmpty(device.getGroupRef()) && ! originalDevice.getGroupRef().equalsIgnoreCase(device.getGroupRef())) { + originalDevice.setGroupRef(device.getGroupRef()); + } + if(CollectionUtils.isNotEmpty(device.getTags())) { + originalDevice.getTags().addAll(device.getTags()); + } + originalDevice.setUpdateDate(String.valueOf(Instant.now().toEpochMilli())); + this.createorUpdateDevice(originalDevice); + } + + /** + * @param device - + * @throws DeviceRegistrationError - + */ + public void checkDeviceExpiry(RegisterDevice device) throws DeviceRegistrationError + { + Long currentTime = Instant.now().toEpochMilli(); + //Date currentDate = new Date(currentTime); + Long activationTime = Long.valueOf(device.getActivationDate()); + // Date activationDate = new Date(activationTime); + + DateTime currentDate = new DateTime(currentTime); + DateTime activationDate = new DateTime(activationTime); + + int days = Days.daysBetween(currentDate, activationDate).getDays(); + + if(Math.abs(days) > Integer.valueOf(this.deactivationPeriod)){ + throw new DeviceRegistrationError("Device has past its activation period."); //$NON-NLS-1$ + } + + } +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/manager/GroupManagementService.java b/src/main/java/com/ge/predix/solsvc/kitservice/manager/GroupManagementService.java new file mode 100644 index 0000000..f4a862c --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/manager/GroupManagementService.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.manager; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import com.ge.predix.entity.fielddata.Data; +import com.ge.predix.entity.fielddata.FieldData; +import com.ge.predix.entity.fielddata.PredixString; +import com.ge.predix.entity.getfielddata.GetFieldDataRequest; +import com.ge.predix.solsvc.kitservice.boot.utils.FdhUtils; +import com.ge.predix.solsvc.kitservice.model.KitGroup; +import com.ge.predix.solsvc.kitservice.model.UserGroup; + +/** + * + * @author 212421693 - + */ +@Component +public class GroupManagementService extends BaseManager +{ + private static final Logger log = LoggerFactory.getLogger(GroupManagementService.class); + private static final String USER_GROUP = "user-group"; //$NON-NLS-1$ + + + /** + * @param headers - + * @param userId - + * @return - + */ + public UserGroup getUserGroup(List
headers, String userId) + { + UserGroup userGroup = null; + if(StringUtils.isNotEmpty(userId)){ + GetFieldDataRequest request = FdhUtils.createGetUserGroupRequest("/"+USER_GROUP, "PredixString",userId); //$NON-NLS-1$ //$NON-NLS-2$ + List fieldData = getFieldDataResult(request,headers); + if(CollectionUtils.isEmpty(fieldData)) { + return null; + } + Data predixString = fieldData.get(0).getData(); + PredixString data = (PredixString) predixString; + String deviceString = StringEscapeUtils.unescapeJava(data.getString()); + deviceString = deviceString.substring(1, deviceString.length() - 1); + deviceString = deviceString.substring(0, deviceString.length()); + List userGroups = this.jsonMapper.fromJsonArray("["+deviceString+"]", UserGroup.class); //$NON-NLS-1$ //$NON-NLS-2$ + if(CollectionUtils.isNotEmpty(userGroups)) + userGroup = userGroups.get(0); + return userGroup; + + } + return userGroup; + } + + /** + * @param headers - + * @param userGroupRef - + * @param groupRef - + * @param userId - + * @return - + */ + + public String getOrCreateGroup(List
headers, String userGroupRef, String groupRef) + { + + KitGroup group = getGroup(headers,groupRef); + if( group == null) { + group = createGroup(groupRef,userGroupRef); + } + group.getGroupRef().add(userGroupRef); + + List kitModels = new ArrayList<>(); + kitModels.add(group); + return this.jsonMapper.toJson(kitModels); + + } + + /** + * @param headers - + * @param groupRef - + * @param userId - + * @return - + */ + public UserGroup getOrCreateUserGroup(List
headers, String userId) + { + + UserGroup userGroup = getUserGroup(headers,userId); + if(userGroup == null) { + userGroup = createUserGroup(userId); + } + else { + userGroup.getUsers().add(userId); + userGroup.setUpdatedDate(String.valueOf(Instant.now().toEpochMilli())); + } + return userGroup; + + + } + + /** + * + * @param userGroup - + * @return - + */ + public String getUserGroupString(final UserGroup userGroup) { + ArrayList kitModels = new ArrayList<>(); + kitModels.add(userGroup); + return this.jsonMapper.toJson(kitModels); + } + + /** + * @param groupRef + * @param userId + * @return - + */ + private UserGroup createUserGroup(String userId) + { + UserGroup userGroup = new UserGroup(); + userGroup.setUri("/"+USER_GROUP+"/"+UUID.randomUUID().toString()); //$NON-NLS-1$ //$NON-NLS-2$ + userGroup.getOwners().add(userId); + userGroup.getUsers().add(userId); + userGroup.setCreatedDate(String.valueOf(Instant.now().toEpochMilli())); + return userGroup; + + } + + + /** + * + * @param groupRef + * @return - + */ + private KitGroup createGroup(String groupRef,String userGroupRef) + { + KitGroup group = new KitGroup(); + group.setUri(groupRef); + group.setCreatedate(String.valueOf(Instant.now().toEpochMilli())); + group.setDescription(groupRef); + String[] parts = groupRef.split("/"); //$NON-NLS-1$ + if(parts.length > 0 ){ + group.setName(parts[parts.length-1]); + } + group.getGroupRef().add(userGroupRef); + return group; + } + + /** + * @param headers + * @param groupRef + * @return - + */ + private KitGroup getGroup(List
headers, String groupRef) + { + log.info("Calling getGroup for "+groupRef); //$NON-NLS-1$ + KitGroup group = null; + if(StringUtils.isNotEmpty(groupRef)){ + GetFieldDataRequest request = FdhUtils.createGetGroupRequest(groupRef, "PredixString"); //$NON-NLS-1$ + List fieldData = getFieldDataResult(request,headers); + if(CollectionUtils.isEmpty(fieldData)) { + return null; + } + Data predixString = fieldData.get(0).getData(); + PredixString data = (PredixString) predixString; + String deviceString = StringEscapeUtils.unescapeJava(data.getString()); + deviceString = deviceString.substring(1, deviceString.length() - 1); + deviceString = deviceString.substring(0, deviceString.length()); + List groups = this.jsonMapper.fromJsonArray("["+deviceString+"]", KitGroup.class); //$NON-NLS-1$ //$NON-NLS-2$ + if(CollectionUtils.isNotEmpty(groups)) + group = groups.get(0); + return group; + + } + return group; + + + } + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/model/KitGroup.java b/src/main/java/com/ge/predix/solsvc/kitservice/model/KitGroup.java new file mode 100644 index 0000000..bb60fc2 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/model/KitGroup.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.model; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; + +import com.ge.predix.solsvc.bootstrap.ams.dto.Group; + +/** + * + * @author 212421693 - + */ +public class KitGroup extends Group +{ + /** + * + */ + Set groupRef = new HashSet(); + + /** + * @return the groupRef + */ + public Set getGroupRef() + { + return this.groupRef; + } + + /** + * @param groupRef the groupRef to set + */ + public void setGroupRef(Set groupRef) + { + this.groupRef = groupRef; + } + + /* (non-Javadoc) + * @see com.ge.predix.solsvc.bootstrap.ams.dto.Group#equals(java.lang.Object) + */ + @Override + public boolean equals(Object other) + { + return EqualsBuilder.reflectionEquals(this, other); + } + + /* (non-Javadoc) + * @see com.ge.predix.solsvc.bootstrap.ams.dto.Group#hashCode() + */ + @Override + public int hashCode() + { + return HashCodeBuilder.reflectionHashCode(this); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/model/RegisterDevice.java b/src/main/java/com/ge/predix/solsvc/kitservice/model/RegisterDevice.java new file mode 100644 index 0000000..30e7a6a --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/model/RegisterDevice.java @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.model; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.validation.constraints.Pattern; + +import com.ge.predix.entity.asset.AssetTag; +import com.ge.predix.solsvc.bootstrap.ams.dto.Tag; + +/** + * + * @author 212421693 - + */ + +public class RegisterDevice +{ + /** + * - + */ + public RegisterDevice() + { + super(); + } + /** + * + */ + String uri; + + /** + * + */ + + String deviceName; + /** + * + */ + String deviceAddress; + /** + * + */ + String deviceType; + /** + * + */ + String activationDate; + /** + * + */ + String groupRef; + /** + * + */ + private String userId; + /** + * + */ + String createdDate; + + /** + * + */ + String updateDate; + + /** + * + */ + Set tags = new HashSet(); + + private Map deviceConfig; + /** + * @return the uri + */ + public String getUri() + { + return this.uri; + } + /** + * @param uri the uri to set + */ + public void setUri(String uri) + { + this.uri = uri; + } + /** + * @return the deviceName + */ + public String getDeviceName() + { + return this.deviceName; + } + /** + * @param deviceName the deviceName to set + */ + public void setDeviceName(String deviceName) + { + this.deviceName = deviceName; + } + /** + * @return the deviceAddress + */ + public String getDeviceAddress() + { + return this.deviceAddress; + } + /** + * @param deviceAddress the deviceAddress to set + */ + public void setDeviceAddress(String deviceAddress) + { + this.deviceAddress = deviceAddress; + } + /** + * @return the deviceType + */ + public String getDeviceType() + { + return this.deviceType; + } + /** + * @param deviceType the deviceType to set + */ + public void setDeviceType(String deviceType) + { + this.deviceType = deviceType; + } + /** + * @return the activationDate + */ + public String getActivationDate() + { + return this.activationDate; + } + /** + * @param activationDate the activationDate to set + */ + public void setActivationDate(String activationDate) + { + this.activationDate = activationDate; + } + /** + * @return the groupRef + */ + public String getGroupRef() + { + return this.groupRef; + } + /** + * @param groupRef the groupRef to set + */ + public void setGroupRef(String groupRef) + { + this.groupRef = groupRef; + } + /** + * @return the createdDate + */ + public String getCreatedDate() + { + return this.createdDate; + } + /** + * @param createdDate the createdDate to set + */ + public void setCreatedDate(String createdDate) + { + this.createdDate = createdDate; + } + /** + * @return the tags + */ + public Set getTags() + { + return this.tags; + } + /** + * @param tags the tags to set + */ + public void setTags(Set tags) + { + this.tags = tags; + } + /** + * @return the userId + */ + public String getUserId() + { + return this.userId; + } + /** + * @param userId the userId to set + */ + public void setUserId(String userId) + { + this.userId = userId; + } + /** + * @return the deviceConfig + */ + public Map getDeviceConfig() + { + return this.deviceConfig; + } + /** + * @param deviceConfig the deviceConfig to set + */ + public void setDeviceConfig(Map deviceConfig) + { + this.deviceConfig = deviceConfig; + } + /** + * @return the updateDate + */ + public String getUpdateDate() + { + return this.updateDate; + } + /** + * @param updateDate the updateDate to set + */ + public void setUpdateDate(String updateDate) + { + this.updateDate = updateDate; + } + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/model/UserGroup.java b/src/main/java/com/ge/predix/solsvc/kitservice/model/UserGroup.java new file mode 100644 index 0000000..320dc99 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/model/UserGroup.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.model; + +import java.util.HashSet; +import java.util.Set; + +/** + * User Group reference + * + * @author 212421693 - + */ +public class UserGroup +{ + + private String uri; + /** + * + */ + Set users = new HashSet(); + /** + * + */ + Set owners = new HashSet(); + + /** + * + */ + String createdDate; + /** + * + */ + String updatedDate; + /** + * @return the uri + */ + public String getUri() + { + return this.uri; + } + /** + * @param uri the uri to set + */ + public void setUri(String uri) + { + this.uri = uri; + } + /** + * @return the users + */ + public Set getUsers() + { + return this.users; + } + /** + * @param users the users to set + */ + public void setUsers(Set users) + { + this.users = users; + } + /** + * @return the owners + */ + public Set getOwners() + { + return this.owners; + } + /** + * @param owners the owners to set + */ + public void setOwners(Set owners) + { + this.owners = owners; + } + + /** + * @return the createdDate + */ + public String getCreatedDate() + { + return this.createdDate; + } + /** + * @param createdDate the createdDate to set + */ + public void setCreatedDate(String createdDate) + { + this.createdDate = createdDate; + } + /** + * @return the updatedDate + */ + public String getUpdatedDate() + { + return this.updatedDate; + } + /** + * @param updatedDate the updatedDate to set + */ + public void setUpdatedDate(String updatedDate) + { + this.updatedDate = updatedDate; + } + + +} diff --git a/src/main/java/com/ge/predix/solsvc/kitservice/validator/RegisterDeviceValidation.java b/src/main/java/com/ge/predix/solsvc/kitservice/validator/RegisterDeviceValidation.java new file mode 100644 index 0000000..f5a94b5 --- /dev/null +++ b/src/main/java/com/ge/predix/solsvc/kitservice/validator/RegisterDeviceValidation.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.kitservice.validator; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.springframework.validation.Errors; +import org.springframework.validation.ValidationUtils; +import org.springframework.validation.Validator; + +import com.ge.predix.solsvc.kitservice.model.RegisterDevice; + +/** + * + * @author 212421693 - + */ +public class RegisterDeviceValidation implements Validator +{ + + + private Pattern pattern; + private Pattern deviceTypePattern; + private Pattern groupRefPattern; + + @SuppressWarnings("javadoc") + public static final String DEVICE_NAME_PATTERN = "^[A-Za-z0-9-]*$"; //$NON-NLS-1$ + @SuppressWarnings("javadoc") + public static final String DEVICE_TYPE_PATTERN = "^[A-Za-z0-9]*$"; //$NON-NLS-1$ + @SuppressWarnings("javadoc") + public static final String GROUP_REF_PATTERN = "^[A-Za-z0-9-/]*$"; //$NON-NLS-1$ + @SuppressWarnings("javadoc") + public static final int DEVICE_ADDRESS_LENGTH = 75; + @SuppressWarnings("javadoc") + public static final int DEVICE_NAME_LENGTH = 50; + + + /** + * - + */ + public RegisterDeviceValidation() + { + this.pattern = Pattern.compile(DEVICE_NAME_PATTERN); + this.deviceTypePattern = Pattern.compile(DEVICE_TYPE_PATTERN); + this.groupRefPattern = Pattern.compile(GROUP_REF_PATTERN); + } + + + /* (non-Javadoc) + * @see org.springframework.validation.Validator#supports(java.lang.Class) + */ + @Override + public boolean supports(Class clazz) + { + return RegisterDevice.class.equals(clazz); + } + + /* (non-Javadoc) + * @see org.springframework.validation.Validator#validate(java.lang.Object, org.springframework.validation.Errors) + */ + @Override + public void validate(Object target, Errors errors) + { + RegisterDevice device = (RegisterDevice) target; + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "deviceName", "field.required"); //$NON-NLS-1$//$NON-NLS-2$ + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "deviceAddress", "field.required"); //$NON-NLS-1$//$NON-NLS-2$ + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "deviceType", "field.required"); //$NON-NLS-1$//$NON-NLS-2$ + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userId", "field.required"); //$NON-NLS-1$//$NON-NLS-2$ + ValidationUtils.rejectIfEmptyOrWhitespace(errors, "groupRef", "field.required"); //$NON-NLS-1$//$NON-NLS-2$ + + + if(!validate(device.getDeviceName() , this.pattern)){ + errors.rejectValue("DeviceName", "Device Name should match ^[A-Za-z0-9-]*"); //$NON-NLS-1$//$NON-NLS-2$ + } + if(!validate(device.getDeviceAddress(),this.pattern)){ + errors.rejectValue("DeviceAddress", "Device Address should match ^[A-Za-z0-9-]*"); //$NON-NLS-1$//$NON-NLS-2$ + } + if(!validate(device.getDeviceType(),this.deviceTypePattern)){ + errors.rejectValue("DeviceType", "Device Type should match ^[A-Za-z0-9]*"); //$NON-NLS-1$//$NON-NLS-2$ + } + if(!validate(device.getGroupRef(),this.groupRefPattern)){ + errors.rejectValue("GroupRef", "GroupRef should match ^[A-Za-z0-9-/]*"); //$NON-NLS-1$//$NON-NLS-2$ + } + + if(DEVICE_NAME_LENGTH <= device.getDeviceName().length() ){ + errors.rejectValue("DeviceName", "Device Name is limited to max 50"); //$NON-NLS-1$//$NON-NLS-2$ + } + if( DEVICE_ADDRESS_LENGTH <= device.getDeviceAddress().length()){ + errors.rejectValue("DeviceAddress", "Device Address is limited to max 75"); //$NON-NLS-1$//$NON-NLS-2$ + } + } + + + /** + * @param deviceName - + * @param pattern + * @return - + */ + public static boolean validate(String deviceName, Pattern pattern) + { + Matcher matcher = pattern.matcher(deviceName); + return matcher.matches(); + } + +} diff --git a/src/main/resources/META-INF/application-security.xml b/src/main/resources/META-INF/application-security.xml new file mode 100644 index 0000000..3fc7224 --- /dev/null +++ b/src/main/resources/META-INF/application-security.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${accessTokenEndpointUrl} + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/application-default.properties b/src/main/resources/application-default.properties new file mode 100644 index 0000000..c7d36d5 --- /dev/null +++ b/src/main/resources/application-default.properties @@ -0,0 +1,14 @@ +#properties used by both main and test code paths - so you don't have to repeat them + +#src/main/resources/application.properties are embedded in jar but are not in eclipse classpath so tests can't see them + +# Spring Security adds the following headers to the http response +security.basic.enabled=false +security.headers.cache=true +# Enable cache control HTTP headers. +security.headers.content-type=true +# Enable "X-Content-Type-Options" header. +security.headers.frame=true +security.headers.xss=true +security.filter-order=1 + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..7f654b3 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,24 @@ +#See application-default.properties under src/main/resources for properties that are shared for unit tests and production +#put production only properties here +java.docs.url=${JAVA_DOCS_URL} +#accessTokenEndpointUrl=https://2710bf73-6988-4160-a796-81eeaf23855c.predix-uaa.run.aws-usw02-pr.ice.predix.io/oauth/token + +predix.oauth.clientId=you.should.base64encode(put.your.clientId:put.your.clientSecret separated by a colon) +predix.asset.restHost=put.your.asset.service.instance.host.here.not.the.url +predix.asset.zoneid=put.your.asset.service.instance.zone.id + + +predix.timeseries.queryUrl=#willGetFromVCAP +predix.timeseries.zoneid=#willGetFromVCAPInstanceId +predix.timeseries.websocket.uri=#willGetFromVCAP + +logging.level.root=${logging_level_root} +logging.level.org.springframework=${logging_level_org_springframework} +logging.level.com.ge.predix.solsvc=${logging_level_com_ge_predix_solsvc} + +#default date for deactivation +register.device.deactivation=${registration_deactivation} + +#view in cloud application +kit.webapp.url=${KIT_CLOUD_APP_URL} +kit.device.credentials=${kit_device_credentials} \ No newline at end of file diff --git a/src/main/resources/asset-model/device-asset-tags.json b/src/main/resources/asset-model/device-asset-tags.json new file mode 100644 index 0000000..fef1e7e --- /dev/null +++ b/src/main/resources/asset-model/device-asset-tags.json @@ -0,0 +1,84 @@ +[{ + "complexType": "AssetTag", + "label": "Rotary Angle", + "tagUri": "/tag/rotaryangle", + "unit": "degrees", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:rotaryangle" + } + }, + { + "complexType": "AssetTag", + "label": "Light", + "tagUri": "/tag/light", + "unit": "lumens", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:light" + } + }, + { + "complexType": "AssetTag", + "label": "Temperature", + "tagUri": "/tag/temperature", + "unit": "F", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:temperature" + } + }, + { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:button" + } + }, + { + "complexType": "AssetTag", + "label": "Sound", + "tagUri": "/tag/sound", + "unit": "dB", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:sound" + } + }, + { + "complexType": "AssetTag", + "label": "Vibration", + "tagUri": "/tag/vibration", + "unit": "m/s2", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:vibration" + } + }, + { + "complexType": "AssetTag", + "label": "Touch", + "tagUri": "/tag/touch", + "unit": "psi", + "hiAlarmThreshold": 80, + "loAlarmThreshold": 65, + "timeseriesDatasource": { + "complexType": "TimeseriesDatasource", + "tag": "${DEVICE_ADDRESS}:touch" + } + } +] diff --git a/src/main/resources/asset-model/kit-asset-model-metadata.json b/src/main/resources/asset-model/kit-asset-model-metadata.json new file mode 100644 index 0000000..4c2935a --- /dev/null +++ b/src/main/resources/asset-model/kit-asset-model-metadata.json @@ -0,0 +1,47 @@ +{ + "putFieldDataCriteria": [ + { + "namespaces": [], + "fieldData": { + "field": [ + { + "fieldIdentifier": { + "complexType": "FieldIdentifier", + "source": "PREDIX_ASSET" + }, + "parents": [] + } + ], + "data": { + "complexType": "MetaData", + "name": "predix-kit-nuc", + "description": "Asset Model for Predix Kit Cloud App", + "source": "PREDIX_ASSET", + "tags": [ + "Aviation", + "Locomotive", + "Windfarm", + "Healthcare" + ] + } + } + }, + { + "namespaces": [], + "fieldData": { + "field": [ + { + "fieldIdentifier": { + "complexType": "FieldIdentifier", + "source": "PREDIX_ASSET" + }, + "parents": [] + } + ], + "data": { + "complexType": "DataFile" + } + } + } + ] +} diff --git a/src/main/resources/asset-model/kit-asset-model.json b/src/main/resources/asset-model/kit-asset-model.json new file mode 100644 index 0000000..0944259 --- /dev/null +++ b/src/main/resources/asset-model/kit-asset-model.json @@ -0,0 +1,114 @@ +[ + { + "complexType": "Asset", + "uri": "/industrial-asset/jet-engine", + "classificationUri": "/classification/JET-ENGINE", + "assetId": "jet-engine", + "description": "GEnx-1B Jet Engine", + "filter": "group=/group/nuc", + "group": "/group/nuc", + "assetTag": { + "for-button": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-sound": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-light": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-temperature": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-rotary": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-vibration": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + }, + "for-touch": { + "complexType": "AssetTag", + "label": "Button", + "tagUri": "/tag/button", + "isKpi": true + } + }, + "attributes": { + "manufacturer": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "GE Aviation" + ] + }, + "firstRun": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "2006" + ] + }, + "applications": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "Boeing 787 Dreamliner", + "Boeing 747-8" + ] + }, + "fuelEfficiency": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "15% savings over GE CF6" + ] + }, + "CO2Efficiency": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "15% savings over GE CF6" + ] + }, + "thrust": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "TakeOff Thrust 57,400 lbf" + ] + }, + "production": { + "complexType": "Attribute", + "type": "string", + "enumeration": [], + "value": [ + "Over 1600 engines on order" + ] + } + } + } +] diff --git a/src/main/resources/asset-model/model-tags.json b/src/main/resources/asset-model/model-tags.json new file mode 100644 index 0000000..15b389f --- /dev/null +++ b/src/main/resources/asset-model/model-tags.json @@ -0,0 +1,41 @@ +[{ + "uri": "/tag/rotaryangle", + "name": "Rotary Angle", + "description": "Rotary Angle", + "dataType": "number", + "tagType": "Continuous", + "defaultTag": [] + }, + { + "uri": "/tag/light", + "name": "Light", + "description": "Light", + "dataType": "number", + "tagType": "Continuous", + "defaultTag": [] + }, + { + "uri": "/tag/temperature", + "name": "Temperature", + "description": "Temperature", + "dataType": "number", + "tagType": "Continuous", + "defaultTag": [] + }, + { + "uri": "/tag/button", + "name": "Button", + "description": "Button", + "dataType": "number", + "tagType": "Continuous", + "defaultTag": [] + }, + { + "uri": "/tag/led", + "name": "Led", + "description": "Led", + "dataType": "number", + "tagType": "Continuous", + "defaultTag": [] + } +] \ No newline at end of file diff --git a/src/main/resources/javadoc-override/stylesheet.css b/src/main/resources/javadoc-override/stylesheet.css new file mode 100644 index 0000000..551a50e --- /dev/null +++ b/src/main/resources/javadoc-override/stylesheet.css @@ -0,0 +1,573 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.useSummary td.colFirst, .useSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..456b8a5 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,15 @@ + + + + Getting Started: Predix Microservice templates + + + +

Greetings from Predix Spring Boot!

+
+

Explore your Microservice

+

Api explorer

+

Microservice Health

+

Docs

+ + \ No newline at end of file diff --git a/src/test/java/com/ge/predix/solsvc/service/AbstractBaseControllerIT.java b/src/test/java/com/ge/predix/solsvc/service/AbstractBaseControllerIT.java new file mode 100644 index 0000000..bc08941 --- /dev/null +++ b/src/test/java/com/ge/predix/solsvc/service/AbstractBaseControllerIT.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.service; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.IntegrationTest; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.web.WebAppConfiguration; + +import com.ge.predix.solsvc.kitservice.boot.Application; + +/** + * + * @author 212421693 - + */ +@RunWith(SpringJUnit4ClassRunner.class) +@SpringApplicationConfiguration(classes = Application.class) +@WebAppConfiguration +@IntegrationTest({"server.port=9092"}) +public abstract class AbstractBaseControllerIT +{ + +} diff --git a/src/test/java/com/ge/predix/solsvc/service/HelloControllerIT.java b/src/test/java/com/ge/predix/solsvc/service/HelloControllerIT.java new file mode 100644 index 0000000..453da88 --- /dev/null +++ b/src/test/java/com/ge/predix/solsvc/service/HelloControllerIT.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.service; + +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.assertThat; + +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +/** + * + * @author 212421693 - + */ +public class HelloControllerIT extends AbstractBaseControllerIT +{ + @Value("${local.server.port}") + private int localServerPort; + + private URL base; + private RestTemplate template; + + /** + * @throws Exception - + */ + @Before + public void setUp() throws Exception { + this.template = new TestRestTemplate(); + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void getHealth() throws Exception { + this.base = new URL("http://localhost:" + this.localServerPort + "/health"); + ResponseEntity response = this.template.getForEntity(this.base.toString(), String.class); + assertThat(response.getBody(), startsWith("{\"status\":\"up\"")); + + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void getEcho() throws Exception { + this.base = new URL("http://localhost:" + this.localServerPort + "/echo"); + ResponseEntity response = this.template.getForEntity(this.base.toString(), String.class); + assertThat(response.getBody(), startsWith("Greetings from Predix Spring Boot! echo=")); + + } + +} diff --git a/src/test/java/com/ge/predix/solsvc/service/KitControllerIT.java b/src/test/java/com/ge/predix/solsvc/service/KitControllerIT.java new file mode 100644 index 0000000..e29e7b0 --- /dev/null +++ b/src/test/java/com/ge/predix/solsvc/service/KitControllerIT.java @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2017 General Electric Company. All rights reserved. + * + * The copyright to the computer software herein is the property of + * General Electric Company. The software may be used and/or copied only + * with the written permission of General Electric Company or in accordance + * with the terms and conditions stipulated in the agreement/contract + * under which the software has been supplied. + */ + +package com.ge.predix.solsvc.service; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.net.URL; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import org.apache.http.Header; +import org.apache.http.ParseException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.message.BasicHeader; +import org.apache.http.util.EntityUtils; +import org.joda.time.DateTime; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.TestRestTemplate; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.security.oauth2.client.OAuth2RestTemplate; +import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails; +import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails; +import org.springframework.security.oauth2.common.OAuth2AccessToken; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ge.predix.solsvc.ext.util.JsonMapper; +import com.ge.predix.solsvc.kitservice.model.RegisterDevice; +import com.ge.predix.solsvc.restclient.config.IOauthRestConfig; +import com.ge.predix.solsvc.restclient.impl.RestClient; + +/** + * + * @author 212421693 - + */ +public class KitControllerIT extends AbstractBaseControllerIT +{ + + private static final Logger log = LoggerFactory.getLogger(KitControllerIT.class); + + @Value("${local.server.port}") + private int localServerPort; + + private URL base; + private RestTemplate template; + + @Autowired + private RestClient restClient; + + @Autowired + @Qualifier("defaultOauthRestConfig") + private IOauthRestConfig restConfig; + + @Autowired + private JsonMapper jsonMapper; + private ObjectMapper objectMapper; + + /** + * @throws Exception - + */ + @Before + public void setUp() + throws Exception + { + this.template = new TestRestTemplate(); + this.template.getMessageConverters().add(new FormHttpMessageConverter()); + this.template.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); + this.objectMapper = new ObjectMapper(); + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void registerDeviceWithAuthenticationError() + throws Exception + { + this.base = new URL("http://localhost:" + this.localServerPort + "/device/register"); + ResponseEntity response = this.template.getForEntity(this.base.toString(), String.class); + assertThat(response.getBody(), containsString("unauthorized")); + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void registerDevice() + throws Exception + { + + String url = "http://localhost:" + this.localServerPort + "/device/register"; + RegisterDevice device = getRegisterDevice(); + + String req = this.jsonMapper.toJson(device); + log.debug("Register Device Json req is " + this.jsonMapper.toJson(device)); + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.post(url, req, headers, this.restConfig.getDefaultConnectionTimeout(), + this.restConfig.getDefaultSocketTimeout()); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK")); + String body = EntityUtils.toString(response.getEntity()); + assertThat(body, containsString("uri")); + RegisterDevice registeredDevice = this.objectMapper.readValue(body, RegisterDevice.class); + assertTrue(registeredDevice.getUri() != null); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void updateDevice() + throws Exception + { + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + RegisterDevice device = getRegisterDevice(); + String url = "http://localhost:" + this.localServerPort + "/device/" + device.getDeviceAddress(); //$NON-NLS-1$//$NON-NLS-2$ + + RegisterDevice updateDevice = getRegisterDevicebyId(headers,url); + + updateDevice.setDeviceName("UpdateDevice-Test"); + + String req = this.jsonMapper.toJson(updateDevice); + log.debug("update Device Json req is " + this.jsonMapper.toJson(updateDevice)); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.put(url, req, headers, this.restConfig.getDefaultConnectionTimeout(), + this.restConfig.getDefaultSocketTimeout()); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK")); + + RegisterDevice newUpdatedDevice = getRegisterDevicebyId(headers,url); + Assert.assertTrue(newUpdatedDevice.getDeviceName().equalsIgnoreCase(updateDevice.getDeviceName())); + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * @return - + */ + private RegisterDevice getRegisterDevicebyId(List
headers , String url ) + { + RegisterDevice registeredDevice = null; + CloseableHttpResponse response = null; + try + { + response = this.restClient.get(url, headers); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK"));//$NON-NLS-1$ + String body = EntityUtils.toString(response.getEntity()); + registeredDevice = this.objectMapper.readValue(body, RegisterDevice.class); + assertTrue(registeredDevice.getUri() != null); + + } + catch (ParseException | IOException e) + { + e.printStackTrace(); + } + finally + { + if ( response != null ) try + { + response.close(); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + return registeredDevice; + } + + /** + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void registerDeviceValidationFailure() + throws Exception + { + + String url = "http://localhost:" + this.localServerPort + "/device/register"; + RegisterDevice device = getRegisterDevice(); + // device.setUserId(""); + //device.setDeviceAddress(""); + device.setDeviceName("!!!!"); + String req = this.jsonMapper.toJson(device); + log.debug("Register Device Json req is " + this.jsonMapper.toJson(device)); + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.post(url, req, headers, this.restConfig.getDefaultConnectionTimeout(), + this.restConfig.getDefaultSocketTimeout()); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 400")); + String body = EntityUtils.toString(response.getEntity()); + assertThat(body, containsString("error")); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void getDevice() + throws Exception + { + RegisterDevice device = getRegisterDevice(); + String url = "http://localhost:" + this.localServerPort + "/device/" + device.getDeviceAddress(); + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.get(url, headers); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK")); + String body = EntityUtils.toString(response.getEntity()); + // assertThat(body, containsString("uri")); + RegisterDevice registeredDevice = this.objectMapper.readValue(body, RegisterDevice.class); + assertTrue(registeredDevice.getUri() != null); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void getDeviceValidation() + throws Exception + { + String url = "http://localhost:" + this.localServerPort + "/device/tinfoil_0481%29"; + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.get(url, headers); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 400")); + String body = EntityUtils.toString(response.getEntity()); + assertThat(body, containsString("error")); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * + * @throws Exception - + */ + @SuppressWarnings("nls") + @Test + public void getAllDevice() + throws Exception + { + String url = "http://localhost:" + this.localServerPort + "/device/"; + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.get(url, headers); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK")); + String body = EntityUtils.toString(response.getEntity()); + List registeredDevices = this.objectMapper.readValue(body, ArrayList.class); + assertTrue(registeredDevices != null); + assertTrue(registeredDevices.size() > 1); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * + * @throws Exception - + */ + @SuppressWarnings({ + "nls", "resource" + }) + @Test + public void checkDeviceActivationExpiry() + throws Exception + { + + String url = "http://localhost:" + this.localServerPort + "/device/register"; + RegisterDevice device = getRegisterDevice(); + device.setUri("/device/testexpiry"); + device.setGroupRef("/group/testexpiry"); + device.setDeviceName("TEST-EXPIRY"); + device.setDeviceAddress("TEST-EXPIRY"); + DateTime lastWeek = new DateTime().minusDays(60+1); + device.setActivationDate(String.valueOf(lastWeek.getMillis())); + String req = this.jsonMapper.toJson(device); + log.debug("Register Device Json req is " + this.jsonMapper.toJson(device)); + List
headers = new ArrayList
(); + String userToken = getUserToken("app_user_1", "app_user_1"); + System.out.println("user token" +userToken); + headers.add(new BasicHeader("Authorization", userToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.post(url, req, headers, this.restConfig.getDefaultConnectionTimeout(), + this.restConfig.getDefaultSocketTimeout()); + Assert.assertNotNull(response); + System.out.println("in here "+response.toString()); + // first time response is 200OK, next time its a validation failure due to expire time check + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK") || (response.toString().contains("400 Bad Request") )); + String geturl = "http://localhost:" + this.localServerPort + "/device/"+device.getDeviceAddress(); + response = this.restClient.get(geturl, headers); + String body = EntityUtils.toString(response.getEntity()); + assertThat(body, containsString("Device has past its activation period.")); + + } + finally + { + if ( response != null ) response.close(); + } + } + + /** + * @return - + */ + private RegisterDevice getRegisterDevice() + { + RegisterDevice device = new RegisterDevice(); + // device.setUri("/device/test-guid"); //$NON-NLS-1$ + device.setActivationDate(String.valueOf(Instant.now().toEpochMilli())); + // device.setCreatedDate(String.valueOf(Instant.now().toEpochMilli())); + device.setDeviceName("NUC-124-test-2"); //$NON-NLS-1$ + device.setDeviceAddress("NUC-124-test-2"); //$NON-NLS-1$ + device.setDeviceType("NUC"); //$NON-NLS-1$ + device.setGroupRef("/group/testcompany-2"); //$NON-NLS-1$ + // device.setUserId("bd9f70a3-8aaa-490b-b2a8-91ba59e58f0f"); //$NON-NLS-1$ + device.setUri("/device/" + device.getDeviceAddress()); //$NON-NLS-1$ + return device; + } + + /** + * Returns a OAuth2RestTemplate based on the username password + */ + + private String getUserToken(String username, String password) + { + // get token here based on username password; + ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails(); + resourceDetails.setUsername(username); + resourceDetails.setPassword(password); + + String url = this.restConfig.getOauthIssuerId(); + + resourceDetails.setAccessTokenUri(url); + + String[] clientIds = this.restConfig.getOauthClientId().split(":"); + resourceDetails.setClientId(clientIds[0]); + resourceDetails.setClientSecret(clientIds[1]); + + OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails); + OAuth2AccessToken token = restTemplate.getAccessToken(); + + return token.getTokenType() + " " + token.getValue(); + } + + + private String getClientToken(String clientId, String secret) + { + ClientCredentialsResourceDetails clientCreds = new ClientCredentialsResourceDetails(); + String url = this.restConfig.getOauthIssuerId(); + clientCreds.setAccessTokenUri(url); + clientCreds.setClientId(clientId); + clientCreds.setClientSecret(secret); + OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(clientCreds); + OAuth2AccessToken token = restTemplate.getAccessToken(); + return token.getTokenType() + " " + token.getValue(); + } + + + + @SuppressWarnings("nls") + @Test + public void getMachineDevice() + throws Exception + { + RegisterDevice device = getRegisterDevice(); + String url = "http://localhost:" + this.localServerPort + "/device/" + device.getDeviceAddress(); + List
headers = new ArrayList
(); + String clientToken = getClientToken("device_client_id", "secret"); + headers.add(new BasicHeader("Authorization", clientToken)); + headers.add(new BasicHeader("Content-Type", "application/json")); + + CloseableHttpResponse response = null; + try + { + response = this.restClient.get(url, headers); + Assert.assertNotNull(response); + Assert.assertTrue(response.toString().contains("HTTP/1.1 200 OK")); + String body = EntityUtils.toString(response.getEntity()); + // assertThat(body, containsString("uri")); + RegisterDevice registeredDevice = this.objectMapper.readValue(body, RegisterDevice.class); + assertTrue(registeredDevice.getUri() != null); + + } + finally + { + if ( response != null ) response.close(); + } + } + +}