From 6c4672dbb3cccd6c7d8cdfde2f59a97af7cfac42 Mon Sep 17 00:00:00 2001 From: Vlastimil Starec Date: Tue, 14 Apr 2020 21:49:47 +0200 Subject: Perform repository cleanup 1. Perform whitespace cleanup in source files Changes are almost exclusively in indentation and line breaks. Some safe spelling fixes may had gotten staged too. 2. Update license file and license headers on java files Change "2019" to "2019-2020" (fix 2017-2018 in some cases). Convert to block comment format. Make "Orange Intellectual Property" consistent across headers. 3. Prepend javascript files with license headers 4. Rename frontend filenames to lowercase 5. Add missing semicolons after statements in react files Issue-ID: AAI-2861 Signed-off-by: Vlastimil Starec Change-Id: Ieee5562ce9e360da3db1f990a6cf4c1b1e56f657 --- LICENSE.md | 2 +- README.md | 8 +- graphgraph-fe/package.json | 78 +-- graphgraph-fe/src/App.css | 53 -- graphgraph-fe/src/App.js | 124 ---- graphgraph-fe/src/App.test.js | 9 - graphgraph-fe/src/DownloadExport.js | 29 - graphgraph-fe/src/Graph.css | 20 - graphgraph-fe/src/Graph.js | 342 ----------- graphgraph-fe/src/GraphHops.css | 9 - graphgraph-fe/src/GraphHops.js | 70 --- graphgraph-fe/src/GraphInfoMenu.css | 73 --- graphgraph-fe/src/GraphInfoMenu.js | 67 -- graphgraph-fe/src/GraphSettings.css | 36 -- graphgraph-fe/src/GraphSettings.js | 239 -------- graphgraph-fe/src/GraphSettingsMenu.css | 12 - graphgraph-fe/src/GraphSettingsMenu.js | 24 - graphgraph-fe/src/PathBreadCrumb.js | 26 - graphgraph-fe/src/PopupSettings.css | 16 - graphgraph-fe/src/PopupSettings.js | 27 - graphgraph-fe/src/ValidationModal.css | 31 - graphgraph-fe/src/ValidationModal.js | 49 -- graphgraph-fe/src/app.css | 53 ++ graphgraph-fe/src/app.js | 152 +++++ graphgraph-fe/src/app.test.js | 29 + graphgraph-fe/src/constants.js | 24 +- graphgraph-fe/src/download_export.js | 43 ++ graphgraph-fe/src/graph.css | 19 + graphgraph-fe/src/graph.js | 372 ++++++++++++ graphgraph-fe/src/graph_hops.css | 8 + graphgraph-fe/src/graph_hops.js | 79 +++ graphgraph-fe/src/graph_info_menu.css | 72 +++ graphgraph-fe/src/graph_info_menu.js | 81 +++ graphgraph-fe/src/graph_settings.css | 36 ++ graphgraph-fe/src/graph_settings.js | 256 ++++++++ graphgraph-fe/src/graph_settings_menu.css | 11 + graphgraph-fe/src/graph_settings_menu.js | 45 ++ graphgraph-fe/src/index.css | 18 +- graphgraph-fe/src/index.js | 36 +- graphgraph-fe/src/path_breadcrumb.js | 46 ++ graphgraph-fe/src/popup_settings.css | 15 + graphgraph-fe/src/popup_settings.js | 40 ++ graphgraph-fe/src/requests.js | 52 +- graphgraph-fe/src/serviceWorker.js | 135 ----- graphgraph-fe/src/service_worker.js | 146 +++++ graphgraph-fe/src/validation_modal.css | 31 + graphgraph-fe/src/validation_modal.js | 58 ++ pom.xml | 160 ++--- run.sh | 6 +- src/main/java/org/onap/aai/graphgraph/App.java | 62 +- .../org/onap/aai/graphgraph/ArgumentParser.java | 107 ++-- src/main/java/org/onap/aai/graphgraph/Config.java | 45 +- .../java/org/onap/aai/graphgraph/CorsFilter.java | 62 +- .../org/onap/aai/graphgraph/ModelExporter.java | 415 ++++++------- .../org/onap/aai/graphgraph/SchemaResource.java | 77 ++- .../org/onap/aai/graphgraph/SchemaValidator.java | 158 ++--- .../java/org/onap/aai/graphgraph/dto/Edge.java | 45 +- .../java/org/onap/aai/graphgraph/dto/Graph.java | 45 +- .../java/org/onap/aai/graphgraph/dto/NodeName.java | 41 +- .../org/onap/aai/graphgraph/dto/NodeProperty.java | 44 +- .../java/org/onap/aai/graphgraph/dto/Property.java | 44 +- .../aai/graphgraph/dto/ValidationProblems.java | 55 +- .../aai/graphgraph/reader/BasicSchemaReader.java | 675 ++++++++++----------- .../org/onap/aai/graphgraph/reader/EdgeType.java | 60 +- .../onap/aai/graphgraph/reader/MetadataEdge.java | 112 ++-- .../onap/aai/graphgraph/reader/SchemaReader.java | 45 +- .../aai/graphgraph/reader/SchemaRepository.java | 44 +- .../graphgraph/velocity/VelocityAssociation.java | 204 +++---- .../aai/graphgraph/velocity/VelocityEntity.java | 144 +++-- .../velocity/VelocityEntityProperty.java | 96 ++- .../onap/aai/graphgraph/velocity/VelocityId.java | 51 +- src/main/resources/docker-assembly.xml | 12 +- src/main/resources/etc/auth/realm.properties | 22 +- src/main/resources/model_export.vm | 280 ++++----- src/test/java/org/onap/aai/graphgraph/AppTest.java | 38 +- 75 files changed, 3316 insertions(+), 3034 deletions(-) delete mode 100644 graphgraph-fe/src/App.css delete mode 100644 graphgraph-fe/src/App.js delete mode 100644 graphgraph-fe/src/App.test.js delete mode 100644 graphgraph-fe/src/DownloadExport.js delete mode 100644 graphgraph-fe/src/Graph.css delete mode 100644 graphgraph-fe/src/Graph.js delete mode 100644 graphgraph-fe/src/GraphHops.css delete mode 100644 graphgraph-fe/src/GraphHops.js delete mode 100644 graphgraph-fe/src/GraphInfoMenu.css delete mode 100644 graphgraph-fe/src/GraphInfoMenu.js delete mode 100644 graphgraph-fe/src/GraphSettings.css delete mode 100644 graphgraph-fe/src/GraphSettings.js delete mode 100644 graphgraph-fe/src/GraphSettingsMenu.css delete mode 100644 graphgraph-fe/src/GraphSettingsMenu.js delete mode 100644 graphgraph-fe/src/PathBreadCrumb.js delete mode 100644 graphgraph-fe/src/PopupSettings.css delete mode 100644 graphgraph-fe/src/PopupSettings.js delete mode 100644 graphgraph-fe/src/ValidationModal.css delete mode 100644 graphgraph-fe/src/ValidationModal.js create mode 100644 graphgraph-fe/src/app.css create mode 100644 graphgraph-fe/src/app.js create mode 100644 graphgraph-fe/src/app.test.js create mode 100644 graphgraph-fe/src/download_export.js create mode 100644 graphgraph-fe/src/graph.css create mode 100644 graphgraph-fe/src/graph.js create mode 100644 graphgraph-fe/src/graph_hops.css create mode 100644 graphgraph-fe/src/graph_hops.js create mode 100644 graphgraph-fe/src/graph_info_menu.css create mode 100644 graphgraph-fe/src/graph_info_menu.js create mode 100644 graphgraph-fe/src/graph_settings.css create mode 100644 graphgraph-fe/src/graph_settings.js create mode 100644 graphgraph-fe/src/graph_settings_menu.css create mode 100644 graphgraph-fe/src/graph_settings_menu.js create mode 100644 graphgraph-fe/src/path_breadcrumb.js create mode 100644 graphgraph-fe/src/popup_settings.css create mode 100644 graphgraph-fe/src/popup_settings.js delete mode 100644 graphgraph-fe/src/serviceWorker.js create mode 100644 graphgraph-fe/src/service_worker.js create mode 100644 graphgraph-fe/src/validation_modal.css create mode 100644 graphgraph-fe/src/validation_modal.js diff --git a/LICENSE.md b/LICENSE.md index 3b84f7e..2ecf92c 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright © 2019 Orange Intellectual Property. All rights reserved. +Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3251be3..84ee8e0 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ To start the frontend just run the following command: The UI will be available on http://localhost:3000 -In order to start the webservices run the App.java from your Java IDE (the service runs on localhost port 8080). +In order to start the webservices run the App.java from your Java IDE (the service runs on localhost port 8080). ## Building docker images @@ -22,7 +22,7 @@ In order to start the webservices run the App.java from your Java IDE (the servi ## Running GraphGraph locally -You have to start a local instance (i.e. localhost) of schema-service. Afterwards build the GraphGraph JAR file with: +You have to start a local instance (i.e. localhost) of schema-service. Afterwards build the GraphGraph JAR file with: ### `mvn clean install` @@ -30,6 +30,6 @@ Go into the target directory and run the JAR file with -d switch: ### `java -jar graphgraph-X.Y.jar -d` -where X.Y is the current version. For more options run the help via: +where X.Y is the current version. For more options run the help via: -### `java -jar graphgraph-X.Y.jar -h` \ No newline at end of file +### `java -jar graphgraph-X.Y.jar -h` diff --git a/graphgraph-fe/package.json b/graphgraph-fe/package.json index eaae97a..a124d60 100644 --- a/graphgraph-fe/package.json +++ b/graphgraph-fe/package.json @@ -1,41 +1,41 @@ { - "name": "graphgraph-fe", - "version": "0.0.1", - "private": true, - "dependencies": { - "bootstrap-css-only": "3.3.7", - "d3": "5.7.0", - "eslint-config-react-app": "3.0.6", - "react": "^16.8.6", - "react-table": "6.10.0", - "react-bootstrap": "0.32.4", - "react-dom": "^16.8.6", - "react-numeric-input": "2.2.3", - "react-scripts": "2.1.1", - "reactjs-popup": "1.3.2", - "underscore": "1.9.1" - }, - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" - }, - "eslintConfig": { - "extends": "react-app" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ], - "devDependencieseslint": { - "eslint": "^5.6.0", - "eslint-config-standard": "^12.0.0", - "eslint-plugin-import": "^2.17.2", - "eslint-plugin-node": "^8.0.1", - "eslint-plugin-promise": "^4.1.1", - "eslint-plugin-standard": "^4.0.0" - } + "name": "graphgraph-fe", + "version": "0.0.1", + "private": true, + "dependencies": { + "bootstrap-css-only": "3.3.7", + "d3": "5.7.0", + "eslint-config-react-app": "3.0.6", + "react": "^16.8.6", + "react-table": "6.10.0", + "react-bootstrap": "0.32.4", + "react-dom": "^16.8.6", + "react-numeric-input": "2.2.3", + "react-scripts": "2.1.1", + "reactjs-popup": "1.3.2", + "underscore": "1.9.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": "react-app" + }, + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ], + "devDependencieseslint": { + "eslint": "^5.6.0", + "eslint-config-standard": "^12.0.0", + "eslint-plugin-import": "^2.17.2", + "eslint-plugin-node": "^8.0.1", + "eslint-plugin-promise": "^4.1.1", + "eslint-plugin-standard": "^4.0.0" + } } diff --git a/graphgraph-fe/src/App.css b/graphgraph-fe/src/App.css deleted file mode 100644 index 74c1327..0000000 --- a/graphgraph-fe/src/App.css +++ /dev/null @@ -1,53 +0,0 @@ -.App { -width: 100%; -height: 100%; -position: absolute; -top: 0; -left: 0; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.root { -width: 100%; -height: 100%; -position: absolute; -top: 0; -left: 0; -} - -.graph-area{ - border-style: solid; - border-color: darkgray; - border-width: 1px 0 1px 0; - position: relative; - width: 100%; - height: 70%; -} diff --git a/graphgraph-fe/src/App.js b/graphgraph-fe/src/App.js deleted file mode 100644 index 788aca1..0000000 --- a/graphgraph-fe/src/App.js +++ /dev/null @@ -1,124 +0,0 @@ -import React from 'react' -import './App.css' -import Graph from './Graph' -import GraphSettingsMenu from './GraphSettingsMenu' -import GraphInfoMenu from './GraphInfoMenu' -import _ from 'underscore' -import { nodeProperty, edgeProperty } from './requests' -import * as constants from './constants' - -var emptyState = { - selectedSchema: '', // currently selected schema - graph: { - nodeNames: [], // names of nodes - edges: [], // edges (each edge has source, target, type and a list of key value properties for tooltip) - paths: [] // all paths between start node and end node - }, - displayedProperties: [], // properties of currently thing (edge or node) - nodeStates: {}, // possible states CLICKED - the currently selected node PATH - currently displayed path - pathIndex: 0, // array index to paths i.e. which path from paths is currently displayed - selectedEdge: { source: 'none', target: 'none' } // defines currently selected edge like like a js object - {source: "pserver", target: "vserver"} -} - -class App extends React.Component { - constructor (props, context) { - super(props, context) - this.graphdata = this.graphdata.bind(this) - this.changePaths = this.changePaths.bind(this) - this.loadNodeProperties = this.loadNodeProperties.bind(this) - this.loadEdgeProperties = this.loadEdgeProperties.bind(this) - this.computeNodeStatesFromPath = this.computeNodeStatesFromPath.bind(this) - this.computeNodeStates = this.computeNodeStates.bind(this) - - this.state = emptyState - } - - loadNodeProperties (nodeName) { - var s = this.state - fetch(nodeProperty(s.selectedSchema, nodeName)) - .then(response => response.json()) - .then(p => { - s['displayedProperties'] = p - s['nodeStates'] = this.computeNodeStates(s['pathIndex']) - // select node - s['nodeStates'][nodeName] = constants.CLICKED - // unselect edge - s['selectedEdge']['source'] = '' - s['selectedEdge']['target'] = '' - this.setState(s) - }) - } - - loadEdgeProperties (source, target) { - var s = this.state - fetch(edgeProperty(s.selectedSchema, source, target)) - .then(response => response.json()) - .then(p => { - s['displayedProperties'] = p - // select edge - s['selectedEdge']['source'] = source - s['selectedEdge']['target'] = target - // unselect node - s['nodeStates'] = this.computeNodeStates(s['pathIndex']) - this.setState(s) - }) - } - - graphdata (data, selectedGraphSchema, graphFingerprint) { - var s = this.state - s['selectedSchema'] = selectedGraphSchema - s['graphFingerprint'] = graphFingerprint - s['graph'] = data - // TODO this should be handled more gracefully ... - if (_.isEmpty(data.edges)) { - alert('The graph has no edges, nothing to display') - } - s['displayedProperties'] = data.startNodeProperties - if (_.isArray(data.paths) && !_.isEmpty(data.paths)) { - s['paths'] = data.paths - s['nodeStates'] = this.computeNodeStatesFromPath(data.paths[0]) - s['pathIndex'] = 0 - } else { - s['paths'] = [] - s['nodeStates'] = {} - } - this.setState(s) - return data - } - - computeNodeStatesFromPath (path) { - return _.reduce(path, (acc, node) => { - acc[node.id] = constants.PATH - return acc - }, {}) - } - - computeNodeStates (pathIndex) { - return this.computeNodeStatesFromPath(this.state.paths[pathIndex]) - } - - changePaths (pathIndex, selectedNode) { - var s = this.state - s['pathIndex'] = pathIndex - this.setState(s) - this.loadNodeProperties(selectedNode) - } - - render () { - let n = _.invert(this.state.nodeStates)[constants.CLICKED] - - let selectedNode = _.isUndefined(n) ? '' : n - return ( -
- -
- -
- - -
- ) - } -} - -export default App diff --git a/graphgraph-fe/src/App.test.js b/graphgraph-fe/src/App.test.js deleted file mode 100644 index 4bf1935..0000000 --- a/graphgraph-fe/src/App.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom' -import App from './App' - -it('renders without crashing', () => { - const div = document.createElement('div') - ReactDOM.render(, div) - ReactDOM.unmountComponentAtNode(div) -}) diff --git a/graphgraph-fe/src/DownloadExport.js b/graphgraph-fe/src/DownloadExport.js deleted file mode 100644 index b031773..0000000 --- a/graphgraph-fe/src/DownloadExport.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import { Button } from 'react-bootstrap' -import { exportSchema } from './requests' - - -class DownloadExport extends React.Component { - constructor (props, context) { - super(props, context) - this.download = this.download.bind(this) - } - - download() { - - setTimeout(() => { - const response = { - file: exportSchema(this.props.schemaVersion), - }; - window.open(response.file); - }, 100); - } - - render() { - return ( - - ); - } -} - -export default DownloadExport diff --git a/graphgraph-fe/src/Graph.css b/graphgraph-fe/src/Graph.css deleted file mode 100644 index 1e5c7d8..0000000 --- a/graphgraph-fe/src/Graph.css +++ /dev/null @@ -1,20 +0,0 @@ -#graph { - height: 100%; - width: 100%; -} - -.arrow { - stroke-width:5; - stroke:#000; - stroke-dasharray:5, 5; -} - -.d3-tip { - line-height: 1; - font-weight: bold; - padding: 12px; - background: rgba(0, 0, 0, 0.8); - color: #fff; - border-radius: 2px; -} - diff --git a/graphgraph-fe/src/Graph.js b/graphgraph-fe/src/Graph.js deleted file mode 100644 index c4b1aa0..0000000 --- a/graphgraph-fe/src/Graph.js +++ /dev/null @@ -1,342 +0,0 @@ -import React from 'react' -import * as d3 from 'd3' -import './Graph.css' -import _ from 'underscore' -import * as constants from './constants' - -const CLICKED_COLOR = 'blue' -const PATH_COLOR = 'red' -const EDGE_MOUSE_OVER_COLOR = 'yellow' -const EDGE_NORMAL_COLOR = '#ccc' -const EDGE_LABEL_COLOR = 'black' -const NODE_NORMAL_COLOR = '#E3E3E3' -const NODE_LABEL_COLOR = 'black' -const NODE_MOUSE_OVER_COLOR = '#F6F6F6' -const NODE_BORDER_COLOR = 'lightgray' - -// variable holds state in order to determine if graph should be redrawn completely -// it breaks the react concept, so a better approach is needed -var graphFingerprint = '' - -var htmlfyProperties = function (properties) { - return "
" + (_.reduce(properties, (html, e) => { return html + "" + e.propertyName + ': ' + e.propertyValue + '
' }, '')) + '
' -} - -var mouseOverEdge = function (edge, div) { - div.transition() - .duration(20) - .style('opacity', 0.9) - div.html(htmlfyProperties(edge.tooltipProperties)) - .style('left', `${d3.event.pageX}px`) - .style('top', `${d3.event.pageY - 28}px`) -} - -var mouseOutEdge = function (edge, div) { - div.transition() - .duration(6000) - .style('opacity', 0) -} - -var addEdgePaths = function (links, g) { - d3.select('body').append('div') - .attr('class', 'tooltip') - .style('opacity', 0) - g.selectAll('.edgepath') - .data(links) - .enter() - .append('path') - .attr('d', d => `M ${d.source.x} ${d.source.y} L ${d.target.x} ${d.target.y}`) - .attr('class', 'edgepath') - .attr('fill-opacity', 0) - .attr('stroke-opacity', 0) - .attr('fill', EDGE_LABEL_COLOR) - .attr('id', (d, i) => `edgepath${i}`) -} - -var chooseColor = function (state) { - if (state === constants.CLICKED) { - return CLICKED_COLOR - } - - if (state === constants.PATH) { - return PATH_COLOR - } - - return NODE_NORMAL_COLOR -} - -var redrawNodeColors = function (nodeStates, selectedEdge) { - d3.selectAll('svg').selectAll('g').selectAll('circle').style('fill', n => chooseColor(nodeStates[n.id])) - d3.selectAll('svg').selectAll('g').selectAll('line').style('stroke', EDGE_NORMAL_COLOR).attr('oldStroke', EDGE_NORMAL_COLOR) - d3.selectAll('svg').selectAll('g').selectAll('line').filter(edge => edge.source.id === selectedEdge.source && edge.target.id === selectedEdge.target).attr('oldStroke', CLICKED_COLOR).style('stroke', CLICKED_COLOR) -} - -var addEdgeLabels = function (links, g, div) { - var edgelabels = g.selectAll('.edgelabel') - .data(links) - .enter() - .append('text') - .attr('class', 'edgelabel') - .attr('text-anchor', 'middle') - .attr('dx', 200) - .attr('dy', 0) - .attr('font-size', '22px') - .attr('id', (d, i) => `edgelabel${i}`) - - edgelabels.append('textPath') - .attr('xlink:href', (d, i) => `#edgepath${i}`) - .text((d, i) => d.type) -} - -var addNodeLabels = function (nodes, g) { - g.selectAll('.nodelabel') - .data(nodes) - .enter() - .append('text') - .attr('x', d => d.x - 14) - .attr('y', d => d.y - 17) - .attr('class', 'nodelabel') - .attr('fill', NODE_LABEL_COLOR) - .attr('font-size', '32px') - .text(d => d.id) - .on('mouseenter', onNodeLabelMouseOver) - .on('mouseout', onNodeLabelMouseOut) -} - -var addLinks = function (links, g, div, edgePropsLoader) { - let ss = _.filter(links, l => l.source.id === l.target.id) - - let selfLinks = _.isUndefined(ss) ? [] : ss - - g.selectAll('ellipse') - .data(selfLinks) - .enter().append('ellipse') - .attr('fill-opacity', 0) - .attr('rx', d => 100) - .attr('ry', d => 16) - .attr('cx', d => d.target.x + 80) - .attr('cy', d => d.target.y) - .style('stroke', NODE_BORDER_COLOR) - .attr('stroke-width', 5) - .on('click', edge => edgePropsLoader(edge.source.id, edge.target.id)) - .on('mouseenter', function (edge) { - mouseOverEdge(edge, div) - d3.select(this) - .transition() - .attr('oldStroke', EDGE_NORMAL_COLOR) - .duration(10) - .style('stroke', EDGE_MOUSE_OVER_COLOR) - }) - .on('mouseleave', function (edge) { - mouseOutEdge(edge, div) - var strokeColor = d3.select(this).attr('oldStroke') - d3.select(this) - .transition() - .duration(300) - .style('stroke', strokeColor) - }) - - g.selectAll('.edgelooplabel') - .data(selfLinks) - .enter() - .append('text') - .attr('x', d => d.source.x + 35) - .attr('y', d => d.source.y + 50) - .attr('class', 'edgelooplabel') - .attr('fill', NODE_LABEL_COLOR) - .attr('font-size', '22px') - .text(d => d.type) - - g.selectAll('line') - .data(links) - .enter().append('line') - .attr('stroke-width', 5) - .attr('x1', d => d.source.x) - .attr('y1', d => d.source.y) - .attr('x2', d => d.target.x) - .attr('y2', d => d.target.y) - .attr('id', (d, i) => `edge${i}`) - .attr('marker-end', 'url(#arrowhead)') - .style('stroke', EDGE_NORMAL_COLOR) - .on('click', edge => edgePropsLoader(edge.source.id, edge.target.id)) - .on('mouseenter', function (edge) { - mouseOverEdge(edge, div) - d3.select(this) - .transition() - .attr('oldStroke', EDGE_NORMAL_COLOR) - .duration(10) - .style('stroke', EDGE_MOUSE_OVER_COLOR) - }) - .on('mouseleave', function (edge) { - mouseOutEdge(edge, div) - var strokeColor = d3.select(this).attr('oldStroke') - d3.select(this) - .transition() - .duration(300) - .style('stroke', strokeColor) - }) -} - -var addMarkers = function (g, svg) { - g.append('defs').append('marker') - .attr('id', 'arrowhead') - .attr('viewBox', '-0 -5 10 10') - .attr('refX', '20') - .attr('refY', '0') - .attr('orient', 'auto') - .attr('markerWidth', '4') - .attr('markerHeight', '4') - .attr('xoverflow', 'visible') - .append('svg:path') - .attr('d', 'M 0,-5 L 10 ,0 L 0,5') - .attr('fill', EDGE_NORMAL_COLOR) - .attr('stroke', EDGE_NORMAL_COLOR) - - var zoomHandler = d3.zoom() - .on('zoom', _ => g.attr('transform', d3.event.transform)) - - zoomHandler(svg) - zoomHandler.translateTo(svg, -7000, -4000) - zoomHandler.scaleTo(svg, 0.08) -} - -var drawGraph = function (nodes, links, g, simulation, svg, addNodes, edgePropsLoader) { - for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); i < n; ++i) { - simulation.tick() - } - - var div = d3.select('body').append('div') - .attr('class', 'tooltip') - .style('opacity', 0) - - addLinks(links, g, div, edgePropsLoader) - addNodes(nodes, g) - addNodeLabels(nodes, g) - addEdgePaths(links, g) - addEdgeLabels(links, g, div) - addMarkers(g, svg) -} - -var prepareLinks = function (nodes, links) { - var result = [] - links.forEach(e => { - var sourceNode = nodes.filter(n => n.id === e.source)[0] - var targetNode = nodes.filter(n => n.id === e.target)[0] - - result.push({ - source: sourceNode, - target: targetNode, - type: e.type, - tooltipProperties: e.tooltipProperties - }) - }) - - return result -} - -var createSimulation = function (nodes, links) { - return d3.forceSimulation(nodes) - .force('charge', d3.forceManyBody().strength(-201)) - .force('link', d3.forceLink(links).distance(1200).strength(1).iterations(400)) - .force('collision', d3.forceCollide().radius(d => 310)) - .force('x', d3.forceX()) - .force('y', d3.forceY()) - .stop() -} - -var createSvg = function () { - var svg = d3.select('#graph').append('svg').attr('height', '100%').attr('width', '100%') - var g = svg.append('g') - - return { 'g': g, 'svg': svg } -} - -var onNodeLabelMouseOut = function () { - d3.select(this) - .transition() - .duration(600) - .attr('font-size', '32px') -} - -var onNodeLabelMouseOver = function () { - d3.select(this) - .transition() - .duration(200) - .attr('font-size', '232px') -} - -var onNodeMouseOver = function () { - var oldFill = d3.select(this).style('fill') - d3.select(this) - .transition() - .duration(200) - .attr('r', 31) - .attr('oldFill', oldFill) - .style('fill', NODE_MOUSE_OVER_COLOR) -} - -var onNodeMouseOut = function (nodeStates) { - var oldFill = d3.select(this).attr('oldFill') - d3.select(this) - .transition() - .duration(300) - .attr('r', 23) - .style('fill', oldFill) -} - -class Graph extends React.Component { - onNodeClick (x) { - // on mouse out the node will change color read from 'oldFill' attribute - d3.selectAll('svg').selectAll('g').selectAll('circle').filter(c => c.id === x.id).attr('oldFill', CLICKED_COLOR) - this.props.nodePropsLoader(x.id) - } - - addNodes (nodes, g) { - g.selectAll('circle') - .data(nodes) - .enter().append('circle') - .attr('cx', d => d.x) - .attr('cy', d => d.y) - .style('fill', n => { - return chooseColor(this.props.nodeStates[n.id]) - }) - .style('stroke', NODE_BORDER_COLOR) - .attr('stroke-width', 3) - .attr('r', 23) - .on('click', this.onNodeClick) - .on('mouseover', onNodeMouseOver) - .on('mouseout', onNodeMouseOut) - } - - reCreateGraph () { - d3.select('#graph').selectAll('*').remove() - - var nodes = this.props.nodes - var links = prepareLinks(this.props.nodes, this.props.edges) - var o = createSvg() - var simulation = createSimulation(nodes, links) - - drawGraph(nodes, links, o.g, simulation, o.svg, this.addNodes, this.props.edgePropsLoader) - } - - constructor (props, context) { - super(props, context) - - this.reCreateGraph = this.reCreateGraph.bind(this) - this.addNodes = this.addNodes.bind(this) - this.onNodeClick = this.onNodeClick.bind(this) - } - - render () { - if (this.props.graphFingerprint !== graphFingerprint) { - this.reCreateGraph() - graphFingerprint = this.props.graphFingerprint - } else { - redrawNodeColors(this.props.nodeStates, this.props.selectedEdge) - } - - return (
) - } -} - -export default Graph diff --git a/graphgraph-fe/src/GraphHops.css b/graphgraph-fe/src/GraphHops.css deleted file mode 100644 index b6207eb..0000000 --- a/graphgraph-fe/src/GraphHops.css +++ /dev/null @@ -1,9 +0,0 @@ - -.hops-input{ -display: flex; -flex-direction: column; -} - -.hops-input-field{ -width: 190px; -} diff --git a/graphgraph-fe/src/GraphHops.js b/graphgraph-fe/src/GraphHops.js deleted file mode 100644 index de7a4cc..0000000 --- a/graphgraph-fe/src/GraphHops.js +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react' -import { Label } from 'react-bootstrap' -import NumericInput from 'react-numeric-input' -import './GraphHops.css' - -var createNumInput = function (label, callback, current) { - return ( -
- - -
- ) -} - -class GraphHops extends React.Component { - constructor (props) { - super(props) - - this.state = { - value: this.props.defaultValue - } - let p = props.parentHops - let c = props.cousinHops - let ch = props.childHops - - this.onChangeParent = (e) => this._onChangeParent(e) - this.onChangeCousin = (e) => this._onChangeCousin(e) - this.onChangeChild = (e) => this._onChangeChild(e) - this.onChange = (hopsName, num) => this._onChange(hopsName, num) - this.state = { parentHops: p, childHops: ch, cousinHops: c } - } - - _onChange (hopsName, num) { - var s = this.state - s[hopsName] = num - this.setState(s) - this.props.updateHops(this.state.parentHops, this.state.cousinHops, this.state.childHops) - } - - _onChangeParent (e) { - this.onChange('parentHops', e) - } - - _onChangeCousin (e) { - this.onChange('cousinHops', e) - } - - _onChangeChild (e) { - this.onChange('childHops', e) - } - - render () { - if (this.props.edgeFilter === 'Edgerules'){ - return ( -
- {createNumInput('edgerule hops', this.onChangeCousin, this.state.cousinHops)} -
- ) - } - - return ( -
- {createNumInput('parent hops', this.onChangeParent, this.state.parentHops)} - {createNumInput('child hops', this.onChangeChild, this.state.childHops)} -
- ) - } -} - -export default GraphHops diff --git a/graphgraph-fe/src/GraphInfoMenu.css b/graphgraph-fe/src/GraphInfoMenu.css deleted file mode 100644 index 24a2719..0000000 --- a/graphgraph-fe/src/GraphInfoMenu.css +++ /dev/null @@ -1,73 +0,0 @@ -.node-property-list { - float:top; - display: flex; - height: 200px; - width: 100%; -} - -.pagination { - margin: 0 12px 0 20px !important; -} - -.fixed-height-container { - overflow: scroll; - float:top; - height: 200px; - width:40%; - padding:3px; - background:white; -} - -.kv-table { - width: 100%; - background: white -} - -.Content -{ - height:224px; - overflow:auto; - background:yellow; -} - - -.breadcrumb > li + li:before { - color: #ccc !important; - content: "> " !important; - padding: 0 5px !important; -} - -.breadcrumb { - margin: 5px 0 0 0 !important; -} - -.path-heading { - margin-top: 6px; - color: #333333; - color: rgb(51, 51, 51); - background-color: #000000; - background-color: rgba(0, 0, 0, 0); - font-size: 14px; - line-height: 20px; - vertical-align: bottom; - letter-spacing: normal; - word-spacing: 0px; - font-weight: 700; - font-style: normal; - font-variant: normal; - text-transform: none; - text-decoration: none; - text-align: left; - text-indent: 0px; -} - -.datatable{ - height: 100%; - width: 100%; -} - -.datatable .row{ - margin-right: 0; - margin-left: 0; -} - diff --git a/graphgraph-fe/src/GraphInfoMenu.js b/graphgraph-fe/src/GraphInfoMenu.js deleted file mode 100644 index d001d50..0000000 --- a/graphgraph-fe/src/GraphInfoMenu.js +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react' -import './GraphInfoMenu.css' -import PathBreadCrumb from './PathBreadCrumb' -import _ from 'underscore' -import ReactTable from "react-table"; -import "react-table/react-table.css"; - -class GraphInfoMenu extends React.Component { - - render () { - var paths = this.props.paths - var callback = this.props.pathCallback - var showPaths = _.isArray(paths) && !_.isEmpty(paths) - var breadcrumbs = _.map(paths, (path, i) => ) - return ( -
-
-

Paths

- {breadcrumbs} -
-
- p.key ? "yes" : "", - minWidth: 20 - }, - { - id: "Index", - Header: "Index", - accessor: p => p.index ? "yes" : "", - minWidth: 20 - }, - { - id: "Required", - Header: "Required", - accessor: p => p.required ? "yes" : "", - minWidth: 20 - } - ]} - defaultPageSize={4} - className="-striped -highlight" - /> -
-
- ) - } -} - -export default GraphInfoMenu diff --git a/graphgraph-fe/src/GraphSettings.css b/graphgraph-fe/src/GraphSettings.css deleted file mode 100644 index 6fb4550..0000000 --- a/graphgraph-fe/src/GraphSettings.css +++ /dev/null @@ -1,36 +0,0 @@ -/* workaround for a bootstrap bug that keeps the last pushed dropdown active after selection */ -.btn-default { - color: #333 !important; - background-color: #fff !important; - border-color: #ccc !important; -} - -.schemas-dropdown{ - width: 100px; -} - -.node-dropdown{ - width: 200px; -} - -.source-dropdown-div{ - margin-left: 20px; - margin-right: 20px; -} - -.startendnode-dropdown{ - display: flex; -} - -.graph-menu -{ - display: flex; - width: 80px !important; -} - - -.modal-button -{ - padding-top: 20px; - margin: 0; -} diff --git a/graphgraph-fe/src/GraphSettings.js b/graphgraph-fe/src/GraphSettings.js deleted file mode 100644 index d511068..0000000 --- a/graphgraph-fe/src/GraphSettings.js +++ /dev/null @@ -1,239 +0,0 @@ -import React from 'react' -import _ from 'underscore' -import { DropdownButton, MenuItem, Label } from 'react-bootstrap' -import './GraphSettings.css' -import Popup from './PopupSettings' -import ValidationModal from './ValidationModal' -import DownloadExport from './DownloadExport' -import { validateSchema, pathGraph, basicGraph, schemas, nodeNames } from './requests' - -var emptyState = { - schemaProblems: [], - nodeNames: [], - fromNode: '', - graph: { - nodeNames: [], - edges: [] - }, - showHops: false, - enableDestinationNode: false, - toNode: '', - edgeFilter: 'Edgerules', - hops: { - parents: 1, - cousin: 1, - child: 1 - }, - selectedSchema: '' -} - -class GraphSettings extends React.Component { - constructor (props, context) { - super(props, context) - this.onChangeStartNode = this.onChangeStartNode.bind(this) - this.onSelectNode = this.onSelectNode.bind(this) - this.selectSchema = this.selectSchema.bind(this) - this.onChangeToNode = this.onChangeToNode.bind(this) - this.loadInitialGraph = this.loadInitialGraph.bind(this) - this.updateHops = this.updateHops.bind(this) - this.changeEdgeFilter = this.changeEdgeFilter.bind(this) - this.graphFingerprint = this.graphFingerprint.bind(this) - this.state = emptyState - } - // this serves as a config 'fingerprint' to know if the d3 visualisation should be redrawn from scratch or just updated - graphFingerprint (schema, from, to, parents, cousin, child, edgeFilter) { - return `${schema}:${from}:${to}:${parents}:${cousin}:${child}:${edgeFilter}` - } - - loadInitialGraph (startNode, endNode, parentHops, cousinHops, childHops, edgeFilter) { - if (this.state.selectedSchema === '' || startNode === 'none') { - var s = this.state - s['edgeFilter'] = edgeFilter - this.setState(s) - return - } - if (startNode === 'all') { - endNode = 'none' - } - - let requestUri = endNode === 'none' - ? basicGraph(this.state.selectedSchema, startNode, parentHops, cousinHops, childHops, edgeFilter) : pathGraph(this.state.selectedSchema, startNode, endNode, edgeFilter) - - fetch(requestUri) - .then(response => response.json()) - .then(g => { - let schema = this.state.selectedSchema - - let f = this.graphFingerprint(schema, startNode, endNode, parentHops, cousinHops, childHops, edgeFilter) - this.props.graphData(g, this.state.selectedSchema, f) - return g - }) - .then(g => { - var s = this.state - s['hops']['parents'] = parentHops - s['hops']['cousin'] = cousinHops - s['hops']['child'] = childHops - s['fromNode'] = startNode - s['toNode'] = endNode - s['graph'] = g - s['edgeFilter'] = edgeFilter - s['showHops'] = endNode === 'none' && startNode !== 'none' && startNode !== 'all' - s['enableDestinationNode'] = startNode !== 'none' && startNode !== 'all' - this.setState(s) - - if (startNode !== 'all') { - this.onSelectNode(startNode) - } - }) - } - - selectSchema (schema) { - var s = this.state - s['selectedSchema'] = schema - fetch(nodeNames(schema, s['edgeFilter'])) - .then(response => response.json()) - .then(nodeNames => { - s['fromNode'] = s['toNode'] = 'none' - s['nodeNames'] = nodeNames - this.setState(s) - }) - fetch(validateSchema(schema)) - .then(response => response.json()) - .then(p => { - s['schemaProblems'] = p.problems - this.setState(s) - }) - } - - changeEdgeFilter (edgeFilter) { - fetch(nodeNames(this.state.selectedSchema, edgeFilter)) - .then(response => response.json()) - .then(nodeNames => { - let s = this.state - s['edgeFilter'] = edgeFilter - s['fromNode'] = s['toNode'] = 'none' - s['nodeNames'] = nodeNames - this.setState(s) - }) - this.loadInitialGraph( - this.state.fromNode, - this.state.toNode, - this.state.hops.parents, - this.state.hops.cousin, - this.state.hops.child, - edgeFilter - ) - } - - updateHops (parentHops, cousinHops, childHops) { - this.loadInitialGraph( - this.state.fromNode, - this.state.toNode, - parentHops, - cousinHops, - childHops, - this.state.edgeFilter) - } - - onChangeToNode (eventKey) { - this.loadInitialGraph(this.state.fromNode, - eventKey, - this.state.hops.parents, - this.state.hops.cousin, - this.state.hops.child, - this.state.edgeFilter) - } - - onSelectNode (eventKey) { - this.props.nodePropsLoader(eventKey) - } - - onChangeStartNode (eventKey) { - this.loadInitialGraph(eventKey, this.state.toNode, - this.state.hops.parents, - this.state.hops.cousin, - this.state.hops.child, - this.state.edgeFilter) - } - - componentDidMount () { - fetch(schemas()) - .then(response => response.json()) - .then(schemas => { - let s = this.state - s['schemas'] = schemas - this.setState(s) - }) - } - - render () { - var schemas = _.map(this.state.schemas, (x, k) => {x}) - - var items = _.map(this.state.nodeNames, (x, k) => {x.id}) - let sortedNames = _.sortBy(this.state.graph.nodeNames, 'id') - var currentNodeNames = _.map(sortedNames, (x, k) => {x.id}) - - var fromItems = items.slice() - fromItems.unshift() - fromItems.unshift(all) - - items.unshift() - items.unshift(none) - - let edgeFilterItems = [ - Edgerules, - Parent-child (OXM structure), - ] - return ( -
-
-
-
- - - {schemas} - -
-
- - - {fromItems} - -
-
- - - {items} - -
-
- - - {edgeFilterItems} - -
-
- - - {currentNodeNames} - -
- - -
- -
- -
- -
- -
- -
-
- ) - } -} - -export default GraphSettings diff --git a/graphgraph-fe/src/GraphSettingsMenu.css b/graphgraph-fe/src/GraphSettingsMenu.css deleted file mode 100644 index 466d07d..0000000 --- a/graphgraph-fe/src/GraphSettingsMenu.css +++ /dev/null @@ -1,12 +0,0 @@ - -.navbar.navbar-adjust{ -margin-bottom: 0px; -} - -.navbar-adjust .container { -margin-left: 0; -} - -.navbar-adjust .container .navbar-header { -margin-right: 250px; -} diff --git a/graphgraph-fe/src/GraphSettingsMenu.js b/graphgraph-fe/src/GraphSettingsMenu.js deleted file mode 100644 index 5ce1e12..0000000 --- a/graphgraph-fe/src/GraphSettingsMenu.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react' -import GraphSettings from './GraphSettings' -import { Navbar, Nav } from 'react-bootstrap' -import './GraphSettingsMenu.css' - -class GraphSettingsMenu extends React.Component { - render () { - return ( - - - - GraphGraph - - - - ) - } -} - -export default GraphSettingsMenu diff --git a/graphgraph-fe/src/PathBreadCrumb.js b/graphgraph-fe/src/PathBreadCrumb.js deleted file mode 100644 index a2c508a..0000000 --- a/graphgraph-fe/src/PathBreadCrumb.js +++ /dev/null @@ -1,26 +0,0 @@ -import _ from 'underscore' -import React from 'react' -import { Breadcrumb } from 'react-bootstrap' - -class PathBreadCrumb extends React.Component { - constructor (props, context) { - super(props, context) - this.pathSelected = this.pathSelected.bind(this) - } - - pathSelected (evt) { - evt.preventDefault() - // the data is only piggyback riding on the "target" property .. not nice but works - this.props.pathCallback(this.props.index, evt.target.getAttribute('target')) - } - - render () { - var path = this.props.path - var callback = this.pathSelected - var items = _.map(path, (item, i) => {item.id} ) - - return ({items}) - } -} - -export default PathBreadCrumb diff --git a/graphgraph-fe/src/PopupSettings.css b/graphgraph-fe/src/PopupSettings.css deleted file mode 100644 index f80e264..0000000 --- a/graphgraph-fe/src/PopupSettings.css +++ /dev/null @@ -1,16 +0,0 @@ -.settings-button { - margin-top: 18px; - margin-left: 15px; -} - -.close.link-button { - background-color: transparent; - border: none; - cursor: pointer; - display: inline; - margin: 10px 0 0 0; - padding: 0; - text-decoration: none; - font-size: 25px; -} - diff --git a/graphgraph-fe/src/PopupSettings.js b/graphgraph-fe/src/PopupSettings.js deleted file mode 100644 index cb8a533..0000000 --- a/graphgraph-fe/src/PopupSettings.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import Popup from 'reactjs-popup' -import './PopupSettings.css' -import GraphHops from './GraphHops' - -class PopupMenu extends React.Component { - render () { - return ( - Hops} position="bottom right"> - {close => ( -
- - -
- )} -
- - ) - } -} - -export default PopupMenu diff --git a/graphgraph-fe/src/ValidationModal.css b/graphgraph-fe/src/ValidationModal.css deleted file mode 100644 index 56b4567..0000000 --- a/graphgraph-fe/src/ValidationModal.css +++ /dev/null @@ -1,31 +0,0 @@ -.modal-content -{ -height: 100%; -width: 100%; -} - -.modal-validator -{ - position: 'fixed'; - width: 1024; - height: 768; - zIndex: 1040; - top: '5%'; - left: '5%'; - border: '1px solid #e5e5e5'; - backgroundColor: 'white'; - boxShadow: '0 5px 15px rgba(0,0,0,.5)'; - padding: 0; -} - -.modal-backdrop -{ - position: 'fixed'; - zIndex: 1040; - top: 0; - bottom: 0; - left: 0; - right: 0; - backgroundColor: '#000'; - opacity: 0.5; -} diff --git a/graphgraph-fe/src/ValidationModal.js b/graphgraph-fe/src/ValidationModal.js deleted file mode 100644 index 8bf1989..0000000 --- a/graphgraph-fe/src/ValidationModal.js +++ /dev/null @@ -1,49 +0,0 @@ -import _ from 'underscore' -import React from 'react' -import './ValidationModal.css' -import { Button, Modal, ListGroup, ListGroupItem } from 'react-bootstrap' - - -class ValidationModal extends React.Component { - constructor(...args) { - super(...args); - this.state = { showModal: false }; - - this.close = () => { - this.setState({ showModal: false }); - }; - - this.open = () => { - this.setState({ showModal: true }); - }; - } - - renderBackdrop(props) { - return
; - } - - render() { - var problems = this.props.schemaProblems - var items = _.map(problems, (problem, i) => {problem} ) - return ( -
- - -
- - {items} - -
-
-
- ); - } -} - -export default ValidationModal diff --git a/graphgraph-fe/src/app.css b/graphgraph-fe/src/app.css new file mode 100644 index 0000000..8c39ae0 --- /dev/null +++ b/graphgraph-fe/src/app.css @@ -0,0 +1,53 @@ +.App { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.App-logo { + animation: App-logo-spin infinite 20s linear; + height: 40vmin; +} + +.App-header { + background-color: #282c34; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); + color: white; +} + +.App-link { + color: #61dafb; +} + +@keyframes App-logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.root { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +.graph-area{ + border-style: solid; + border-color: darkgray; + border-width: 1px 0 1px 0; + position: relative; + width: 100%; + height: 70%; +} diff --git a/graphgraph-fe/src/app.js b/graphgraph-fe/src/app.js new file mode 100644 index 0000000..30eb3d8 --- /dev/null +++ b/graphgraph-fe/src/app.js @@ -0,0 +1,152 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import './app.css'; +import Graph from './graph.js'; +import GraphSettingsMenu from './graph_settings_menu.js'; +import GraphInfoMenu from './graph_info_menu.js'; +import _ from 'underscore'; +import { nodeProperty, edgeProperty } from './requests.js'; +import * as constants from './constants.js'; + +var emptyState = { + // currently selected schema + selectedSchema: '', + graph: { + // names of nodes + nodeNames: [], + // edges (each edge has source, target, type and a list of key value properties for tooltip) + edges: [], + // all paths between start node and end node + paths: [] + }, + // properties of currently thing (edge or node) + displayedProperties: [], + // possible states: + // CLICKED - the currently selected node + // PATH - currently displayed path + nodeStates: {}, + // array index to paths i.e. which path from paths is currently displayed + pathIndex: 0, + // defines currently selected edge like a js object - {source: "pserver", target: "vserver"} + selectedEdge: { source: 'none', target: 'none' } +}; + +class App extends React.Component { + constructor (props, context) { + super(props, context); + this.graphdata = this.graphdata.bind(this); + this.changePaths = this.changePaths.bind(this); + this.loadNodeProperties = this.loadNodeProperties.bind(this); + this.loadEdgeProperties = this.loadEdgeProperties.bind(this); + this.computeNodeStatesFromPath = this.computeNodeStatesFromPath.bind(this); + this.computeNodeStates = this.computeNodeStates.bind(this); + this.state = emptyState; + } + + loadNodeProperties (nodeName) { + var s = this.state; + fetch(nodeProperty(s.selectedSchema, nodeName)) + .then(response => response.json()) + .then(p => { + s['displayedProperties'] = p; + s['nodeStates'] = this.computeNodeStates(s['pathIndex']); + // select node + s['nodeStates'][nodeName] = constants.CLICKED; + // unselect edge + s['selectedEdge']['source'] = ''; + s['selectedEdge']['target'] = ''; + this.setState(s); + }); + } + + loadEdgeProperties (source, target) { + var s = this.state; + fetch(edgeProperty(s.selectedSchema, source, target)) + .then(response => response.json()) + .then(p => { + s['displayedProperties'] = p; + // select edge + s['selectedEdge']['source'] = source; + s['selectedEdge']['target'] = target; + // unselect node + s['nodeStates'] = this.computeNodeStates(s['pathIndex']); + this.setState(s); + }); + } + + graphdata (data, selectedGraphSchema, graphFingerprint) { + var s = this.state; + s['selectedSchema'] = selectedGraphSchema; + s['graphFingerprint'] = graphFingerprint; + s['graph'] = data; + // TODO this should be handled more gracefully ... + if (_.isEmpty(data.edges)) { + alert('The graph has no edges, nothing to display'); + } + s['displayedProperties'] = data.startNodeProperties; + if (_.isArray(data.paths) && !_.isEmpty(data.paths)) { + s['paths'] = data.paths; + s['nodeStates'] = this.computeNodeStatesFromPath(data.paths[0]); + s['pathIndex'] = 0; + } else { + s['paths'] = []; + s['nodeStates'] = {}; + } + this.setState(s); + return data; + } + + computeNodeStatesFromPath (path) { + return _.reduce(path, (acc, node) => { + acc[node.id] = constants.PATH; + return acc; + }, {}); + } + + computeNodeStates (pathIndex) { + return this.computeNodeStatesFromPath(this.state.paths[pathIndex]); + } + + changePaths (pathIndex, selectedNode) { + var s = this.state; + s['pathIndex'] = pathIndex; + this.setState(s); + this.loadNodeProperties(selectedNode); + } + + render () { + let n = _.invert(this.state.nodeStates)[constants.CLICKED]; + + let selectedNode = _.isUndefined(n) ? '' : n; + return ( +
+ +
+ +
+ +
+ ); + } +} + +export default App; diff --git a/graphgraph-fe/src/app.test.js b/graphgraph-fe/src/app.test.js new file mode 100644 index 0000000..893bcbb --- /dev/null +++ b/graphgraph-fe/src/app.test.js @@ -0,0 +1,29 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './app.js'; + +it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + ReactDOM.unmountComponentAtNode(div); +}); diff --git a/graphgraph-fe/src/constants.js b/graphgraph-fe/src/constants.js index 6076e6f..9181850 100644 --- a/graphgraph-fe/src/constants.js +++ b/graphgraph-fe/src/constants.js @@ -1,2 +1,22 @@ -export const CLICKED = 'clicked' -export const PATH = 'on-path' +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +export const CLICKED = 'clicked'; +export const PATH = 'on-path'; diff --git a/graphgraph-fe/src/download_export.js b/graphgraph-fe/src/download_export.js new file mode 100644 index 0000000..21b2829 --- /dev/null +++ b/graphgraph-fe/src/download_export.js @@ -0,0 +1,43 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import { Button } from 'react-bootstrap'; +import { exportSchema } from './requests.js'; + +class DownloadExport extends React.Component { + constructor (props, context) { + super(props, context); + this.download = this.download.bind(this); + } + + download() { + setTimeout(() => { + const response = { file: exportSchema(this.props.schemaVersion) }; + window.open(response.file); + }, 100); + } + + render() { + return ; + } +} + +export default DownloadExport; diff --git a/graphgraph-fe/src/graph.css b/graphgraph-fe/src/graph.css new file mode 100644 index 0000000..0c9460f --- /dev/null +++ b/graphgraph-fe/src/graph.css @@ -0,0 +1,19 @@ +#graph { + height: 100%; + width: 100%; +} + +.arrow { + stroke-width:5; + stroke:#000; + stroke-dasharray:5, 5; +} + +.d3-tip { + line-height: 1; + font-weight: bold; + padding: 12px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; +} diff --git a/graphgraph-fe/src/graph.js b/graphgraph-fe/src/graph.js new file mode 100644 index 0000000..492959a --- /dev/null +++ b/graphgraph-fe/src/graph.js @@ -0,0 +1,372 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import * as d3 from 'd3'; +import './graph.css'; +import _ from 'underscore'; +import * as constants from './constants.js'; + +const CLICKED_COLOR = 'blue'; +const PATH_COLOR = 'red'; +const EDGE_MOUSE_OVER_COLOR = 'yellow'; +const EDGE_NORMAL_COLOR = '#ccc'; +const EDGE_LABEL_COLOR = 'black'; +const NODE_NORMAL_COLOR = '#E3E3E3'; +const NODE_LABEL_COLOR = 'black'; +const NODE_MOUSE_OVER_COLOR = '#F6F6F6'; +const NODE_BORDER_COLOR = 'lightgray'; + +// variable holds state in order to determine if graph should be redrawn completely +// it breaks the react concept, so a better approach is needed +var graphFingerprint = ''; + +var htmlfyProperties = function (properties) { + return "
" + (_.reduce(properties, (html, e) => { + return html + "" + + e.propertyName + ': ' + + e.propertyValue + '
'; + }, '')) + '
'; +}; + +var mouseOverEdge = function (edge, div) { + div.transition() + .duration(20) + .style('opacity', 0.9); + div.html(htmlfyProperties(edge.tooltipProperties)) + .style('left', `${d3.event.pageX}px`) + .style('top', `${d3.event.pageY - 28}px`); +}; + +var mouseOutEdge = function (edge, div) { + div.transition() + .duration(6000) + .style('opacity', 0); +}; + +var addEdgePaths = function (links, g) { + d3.select('body').append('div') + .attr('class', 'tooltip') + .style('opacity', 0); + g.selectAll('.edgepath') + .data(links) + .enter() + .append('path') + .attr('d', d => `M ${d.source.x} ${d.source.y} L ${d.target.x} ${d.target.y}`) + .attr('class', 'edgepath') + .attr('fill-opacity', 0) + .attr('stroke-opacity', 0) + .attr('fill', EDGE_LABEL_COLOR) + .attr('id', (d, i) => `edgepath${i}`); +}; + +var chooseColor = function (state) { + if (state === constants.CLICKED) { + return CLICKED_COLOR; + } + if (state === constants.PATH) { + return PATH_COLOR; + } + return NODE_NORMAL_COLOR; +}; + +var redrawNodeColors = function (nodeStates, selectedEdge) { + d3.selectAll('svg').selectAll('g').selectAll('circle') + .style('fill', n => chooseColor(nodeStates[n.id])); + d3.selectAll('svg').selectAll('g').selectAll('line') + .style('stroke', EDGE_NORMAL_COLOR).attr('oldStroke', EDGE_NORMAL_COLOR); + d3.selectAll('svg').selectAll('g').selectAll('line') + .filter(edge => edge.source.id === selectedEdge.source && edge.target.id === selectedEdge.target) + .attr('oldStroke', CLICKED_COLOR) + .style('stroke', CLICKED_COLOR); +}; + +var addEdgeLabels = function (links, g, div) { + var edgelabels = g.selectAll('.edgelabel') + .data(links) + .enter() + .append('text') + .attr('class', 'edgelabel') + .attr('text-anchor', 'middle') + .attr('dx', 200) + .attr('dy', 0) + .attr('font-size', '22px') + .attr('id', (d, i) => `edgelabel${i}`); + + edgelabels.append('textPath') + .attr('xlink:href', (d, i) => `#edgepath${i}`) + .text((d, i) => d.type); +}; + +var addNodeLabels = function (nodes, g) { + g.selectAll('.nodelabel') + .data(nodes) + .enter() + .append('text') + .attr('x', d => d.x - 14) + .attr('y', d => d.y - 17) + .attr('class', 'nodelabel') + .attr('fill', NODE_LABEL_COLOR) + .attr('font-size', '32px') + .text(d => d.id) + .on('mouseenter', onNodeLabelMouseOver) + .on('mouseout', onNodeLabelMouseOut); +}; + +var addLinks = function (links, g, div, edgePropsLoader) { + let ss = _.filter(links, l => l.source.id === l.target.id); + + let selfLinks = _.isUndefined(ss) ? [] : ss; + + g.selectAll('ellipse') + .data(selfLinks) + .enter().append('ellipse') + .attr('fill-opacity', 0) + .attr('rx', d => 100) + .attr('ry', d => 16) + .attr('cx', d => d.target.x + 80) + .attr('cy', d => d.target.y) + .style('stroke', NODE_BORDER_COLOR) + .attr('stroke-width', 5) + .on('click', edge => edgePropsLoader(edge.source.id, edge.target.id)) + .on('mouseenter', function (edge) { + mouseOverEdge(edge, div); + d3.select(this) + .transition() + .attr('oldStroke', EDGE_NORMAL_COLOR) + .duration(10) + .style('stroke', EDGE_MOUSE_OVER_COLOR); + }) + .on('mouseleave', function (edge) { + mouseOutEdge(edge, div); + var strokeColor = d3.select(this).attr('oldStroke'); + d3.select(this) + .transition() + .duration(300) + .style('stroke', strokeColor); + }); + + g.selectAll('.edgelooplabel') + .data(selfLinks) + .enter() + .append('text') + .attr('x', d => d.source.x + 35) + .attr('y', d => d.source.y + 50) + .attr('class', 'edgelooplabel') + .attr('fill', NODE_LABEL_COLOR) + .attr('font-size', '22px') + .text(d => d.type); + + g.selectAll('line') + .data(links) + .enter().append('line') + .attr('stroke-width', 5) + .attr('x1', d => d.source.x) + .attr('y1', d => d.source.y) + .attr('x2', d => d.target.x) + .attr('y2', d => d.target.y) + .attr('id', (d, i) => `edge${i}`) + .attr('marker-end', 'url(#arrowhead)') + .style('stroke', EDGE_NORMAL_COLOR) + .on('click', edge => edgePropsLoader(edge.source.id, edge.target.id)) + .on('mouseenter', function (edge) { + mouseOverEdge(edge, div); + d3.select(this) + .transition() + .attr('oldStroke', EDGE_NORMAL_COLOR) + .duration(10) + .style('stroke', EDGE_MOUSE_OVER_COLOR); + }) + .on('mouseleave', function (edge) { + mouseOutEdge(edge, div); + var strokeColor = d3.select(this).attr('oldStroke'); + d3.select(this) + .transition() + .duration(300) + .style('stroke', strokeColor); + }); +}; + +var addMarkers = function (g, svg) { + g.append('defs').append('marker') + .attr('id', 'arrowhead') + .attr('viewBox', '-0 -5 10 10') + .attr('refX', '20') + .attr('refY', '0') + .attr('orient', 'auto') + .attr('markerWidth', '4') + .attr('markerHeight', '4') + .attr('xoverflow', 'visible') + .append('svg:path') + .attr('d', 'M 0,-5 L 10 ,0 L 0,5') + .attr('fill', EDGE_NORMAL_COLOR) + .attr('stroke', EDGE_NORMAL_COLOR); + + var zoomHandler = d3.zoom() + .on('zoom', _ => g.attr('transform', d3.event.transform)); + + zoomHandler(svg); + zoomHandler.translateTo(svg, -7000, -4000); + zoomHandler.scaleTo(svg, 0.08); +}; + +var drawGraph = function (nodes, links, g, simulation, svg, addNodes, edgePropsLoader) { + for (var i = 0, n = Math.ceil(Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())); + i < n; ++i) { + simulation.tick(); + } + + var div = d3.select('body').append('div') + .attr('class', 'tooltip') + .style('opacity', 0); + + addLinks(links, g, div, edgePropsLoader); + addNodes(nodes, g); + addNodeLabels(nodes, g); + addEdgePaths(links, g); + addEdgeLabels(links, g, div); + addMarkers(g, svg); +}; + +var prepareLinks = function (nodes, links) { + var result = []; + links.forEach(e => { + var sourceNode = nodes.filter(n => n.id === e.source)[0]; + var targetNode = nodes.filter(n => n.id === e.target)[0]; + + result.push({ + source: sourceNode, + target: targetNode, + type: e.type, + tooltipProperties: e.tooltipProperties + }); + }); + + return result; +}; + +var createSimulation = function (nodes, links) { + return d3.forceSimulation(nodes) + .force('charge', d3.forceManyBody().strength(-201)) + .force('link', d3.forceLink(links).distance(1200).strength(1).iterations(400)) + .force('collision', d3.forceCollide().radius(d => 310)) + .force('x', d3.forceX()) + .force('y', d3.forceY()) + .stop(); +}; + +var createSvg = function () { + var svg = d3.select('#graph').append('svg').attr('height', '100%').attr('width', '100%'); + var g = svg.append('g'); + + return { 'g': g, 'svg': svg }; +}; + +var onNodeLabelMouseOut = function () { + d3.select(this) + .transition() + .duration(600) + .attr('font-size', '32px'); +}; + +var onNodeLabelMouseOver = function () { + d3.select(this) + .transition() + .duration(200) + .attr('font-size', '232px'); +}; + +var onNodeMouseOver = function () { + var oldFill = d3.select(this).style('fill'); + d3.select(this) + .transition() + .duration(200) + .attr('r', 31) + .attr('oldFill', oldFill) + .style('fill', NODE_MOUSE_OVER_COLOR); +}; + +var onNodeMouseOut = function (nodeStates) { + var oldFill = d3.select(this).attr('oldFill'); + d3.select(this) + .transition() + .duration(300) + .attr('r', 23) + .style('fill', oldFill); +}; + +class Graph extends React.Component { + onNodeClick (x) { + // on mouse out the node will change color read from 'oldFill' attribute + d3.selectAll('svg').selectAll('g').selectAll('circle') + .filter(c => c.id === x.id) + .attr('oldFill', CLICKED_COLOR); + this.props.nodePropsLoader(x.id); + } + + addNodes (nodes, g) { + g.selectAll('circle') + .data(nodes) + .enter().append('circle') + .attr('cx', d => d.x) + .attr('cy', d => d.y) + .style('fill', n => { + return chooseColor(this.props.nodeStates[n.id]); + }) + .style('stroke', NODE_BORDER_COLOR) + .attr('stroke-width', 3) + .attr('r', 23) + .on('click', this.onNodeClick) + .on('mouseover', onNodeMouseOver) + .on('mouseout', onNodeMouseOut); + } + + reCreateGraph () { + d3.select('#graph').selectAll('*').remove(); + + var nodes = this.props.nodes; + var links = prepareLinks(this.props.nodes, this.props.edges); + var o = createSvg(); + var simulation = createSimulation(nodes, links); + + drawGraph(nodes, links, o.g, simulation, o.svg, this.addNodes, this.props.edgePropsLoader); + } + + constructor (props, context) { + super(props, context); + + this.reCreateGraph = this.reCreateGraph.bind(this); + this.addNodes = this.addNodes.bind(this); + this.onNodeClick = this.onNodeClick.bind(this); + } + + render () { + if (this.props.graphFingerprint !== graphFingerprint) { + this.reCreateGraph(); + graphFingerprint = this.props.graphFingerprint; + } else { + redrawNodeColors(this.props.nodeStates, this.props.selectedEdge); + } + + return
; + } +} + +export default Graph; diff --git a/graphgraph-fe/src/graph_hops.css b/graphgraph-fe/src/graph_hops.css new file mode 100644 index 0000000..474b661 --- /dev/null +++ b/graphgraph-fe/src/graph_hops.css @@ -0,0 +1,8 @@ +.hops-input{ + display: flex; + flex-direction: column; +} + +.hops-input-field{ + width: 190px; +} diff --git a/graphgraph-fe/src/graph_hops.js b/graphgraph-fe/src/graph_hops.js new file mode 100644 index 0000000..da98db2 --- /dev/null +++ b/graphgraph-fe/src/graph_hops.js @@ -0,0 +1,79 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import { Label } from 'react-bootstrap'; +import NumericInput from 'react-numeric-input'; +import './graph_hops.css'; + +var createNumInput = function (label, callback, current) { + return ( +
+ + +
+ ); +}; + +class GraphHops extends React.Component { + constructor (props) { + super(props); + + this.state = { value: this.props.defaultValue }; + let p = props.parentHops; + let c = props.cousinHops; + let ch = props.childHops; + + this.onChangeParent = (e) => this._onChangeParent(e); + this.onChangeCousin = (e) => this._onChangeCousin(e); + this.onChangeChild = (e) => this._onChangeChild(e); + this.onChange = (hopsName, num) => this._onChange(hopsName, num); + this.state = { parentHops: p, childHops: ch, cousinHops: c }; + } + + _onChange (hopsName, num) { + var s = this.state; + s[hopsName] = num; + this.setState(s); + this.props.updateHops(this.state.parentHops, this.state.cousinHops, this.state.childHops); + } + + _onChangeParent (e) { + this.onChange('parentHops', e); + } + + _onChangeCousin (e) { + this.onChange('cousinHops', e); + } + + _onChangeChild (e) { + this.onChange('childHops', e); + } + + render () { + if (this.props.edgeFilter === 'Edgerules') { + return
{createNumInput('edgerule hops', this.onChangeCousin, this.state.cousinHops)}
; + } + + return
{createNumInput('parent hops', this.onChangeParent, this.state.parentHops)} {createNumInput('child hops', this.onChangeChild, this.state.childHops)}
; + } +} + +export default GraphHops; diff --git a/graphgraph-fe/src/graph_info_menu.css b/graphgraph-fe/src/graph_info_menu.css new file mode 100644 index 0000000..6182210 --- /dev/null +++ b/graphgraph-fe/src/graph_info_menu.css @@ -0,0 +1,72 @@ +.node-property-list { + float:top; + display: flex; + height: 200px; + width: 100%; +} + +.pagination { + margin: 0 12px 0 20px !important; +} + +.fixed-height-container { + overflow: scroll; + float:top; + height: 200px; + width:40%; + padding:3px; + background:white; +} + +.kv-table { + width: 100%; + background: white +} + +.Content +{ + height:224px; + overflow:auto; + background:yellow; +} + + +.breadcrumb > li + li:before { + color: #ccc !important; + content: "> " !important; + padding: 0 5px !important; +} + +.breadcrumb { + margin: 5px 0 0 0 !important; +} + +.path-heading { + margin-top: 6px; + color: #333333; + color: rgb(51, 51, 51); + background-color: #000000; + background-color: rgba(0, 0, 0, 0); + font-size: 14px; + line-height: 20px; + vertical-align: bottom; + letter-spacing: normal; + word-spacing: 0px; + font-weight: 700; + font-style: normal; + font-variant: normal; + text-transform: none; + text-decoration: none; + text-align: left; + text-indent: 0px; +} + +.datatable{ + height: 100%; + width: 100%; +} + +.datatable .row{ + margin-right: 0; + margin-left: 0; +} diff --git a/graphgraph-fe/src/graph_info_menu.js b/graphgraph-fe/src/graph_info_menu.js new file mode 100644 index 0000000..66ffbba --- /dev/null +++ b/graphgraph-fe/src/graph_info_menu.js @@ -0,0 +1,81 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import './graph_info_menu.css'; +import PathBreadcrumb from './path_breadcrumb.js'; +import _ from 'underscore'; +import ReactTable from "react-table"; +import "react-table/react-table.css"; + +class GraphInfoMenu extends React.Component { + render () { + var paths = this.props.paths; + var callback = this.props.pathCallback; + var showPaths = _.isArray(paths) && !_.isEmpty(paths); + var breadcrumbs = _.map( + paths, (path, i) => ); + return ( +
+

Paths

{breadcrumbs}
+
+ p.key ? "yes" : "", + minWidth: 20 + }, + { + id: "Index", + Header: "Index", + accessor: p => p.index ? "yes" : "", + minWidth: 20 + }, + { + id: "Required", + Header: "Required", + accessor: p => p.required ? "yes" : "", + minWidth: 20 + } + ]} defaultPageSize={4} className="-striped -highlight" + /> +
+
+ ); + } +} + +export default GraphInfoMenu; diff --git a/graphgraph-fe/src/graph_settings.css b/graphgraph-fe/src/graph_settings.css new file mode 100644 index 0000000..c30cda9 --- /dev/null +++ b/graphgraph-fe/src/graph_settings.css @@ -0,0 +1,36 @@ +/* workaround for a bootstrap bug that keeps the last pushed dropdown active after selection */ +.btn-default { + color: #333 !important; + background-color: #fff !important; + border-color: #ccc !important; +} + +.schemas-dropdown{ + width: 100px; +} + +.node-dropdown{ + width: 200px; +} + +.source-dropdown-div{ + margin-left: 20px; + margin-right: 20px; +} + +.startendnode-dropdown{ + display: flex; +} + +.graph-menu +{ + display: flex; + width: 80px !important; +} + + +.modal-button +{ + padding-top: 20px; + margin: 0; +} diff --git a/graphgraph-fe/src/graph_settings.js b/graphgraph-fe/src/graph_settings.js new file mode 100644 index 0000000..c8f03f1 --- /dev/null +++ b/graphgraph-fe/src/graph_settings.js @@ -0,0 +1,256 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import _ from 'underscore'; +import { DropdownButton, MenuItem, Label } from 'react-bootstrap'; +import './graph_settings.css'; +import Popup from './popup_settings.js'; +import ValidationModal from './validation_modal.js'; +import DownloadExport from './download_export.js'; +import { validateSchema, pathGraph, basicGraph, schemas, nodeNames } from './requests.js'; + +var emptyState = { + schemaProblems: [], + nodeNames: [], + fromNode: '', + graph: { + nodeNames: [], + edges: [] + }, + showHops: false, + enableDestinationNode: false, + toNode: '', + edgeFilter: 'Edgerules', + hops: { + parents: 1, + cousin: 1, + child: 1 + }, + selectedSchema: '' +}; + +class GraphSettings extends React.Component { + constructor (props, context) { + super(props, context); + this.onChangeStartNode = this.onChangeStartNode.bind(this); + this.onSelectNode = this.onSelectNode.bind(this); + this.selectSchema = this.selectSchema.bind(this); + this.onChangeToNode = this.onChangeToNode.bind(this); + this.loadInitialGraph = this.loadInitialGraph.bind(this); + this.updateHops = this.updateHops.bind(this); + this.changeEdgeFilter = this.changeEdgeFilter.bind(this); + this.graphFingerprint = this.graphFingerprint.bind(this); + this.state = emptyState; + } + + /* this serves as a config 'fingerprint' to know if the d3 visualisation + should be redrawn from scratch or just updated */ + graphFingerprint (schema, from, to, parents, cousin, child, edgeFilter) { + return `${schema}:${from}:${to}:${parents}:${cousin}:${child}:${edgeFilter}`; + } + + loadInitialGraph (startNode, endNode, parentHops, cousinHops, childHops, edgeFilter) { + if (this.state.selectedSchema === '' || startNode === 'none') { + var s = this.state; + s['edgeFilter'] = edgeFilter; + this.setState(s); + return; + } + if (startNode === 'all') { + endNode = 'none'; + } + + let requestUri = endNode === 'none' + ? basicGraph( + this.state.selectedSchema, startNode, parentHops, cousinHops, childHops, edgeFilter) + : pathGraph( + this.state.selectedSchema, startNode, endNode, edgeFilter); + + fetch(requestUri) + .then(response => response.json()) + .then(g => { + let schema = this.state.selectedSchema; + let f = this.graphFingerprint( + schema, startNode, endNode, parentHops, cousinHops, childHops, edgeFilter); + this.props.graphData(g, this.state.selectedSchema, f); + return g; + }) + .then(g => { + var s = this.state; + s['hops']['parents'] = parentHops; + s['hops']['cousin'] = cousinHops; + s['hops']['child'] = childHops; + s['fromNode'] = startNode; + s['toNode'] = endNode; + s['graph'] = g; + s['edgeFilter'] = edgeFilter; + s['showHops'] = endNode === 'none' && startNode !== 'none' && startNode !== 'all'; + s['enableDestinationNode'] = startNode !== 'none' && startNode !== 'all'; + this.setState(s); + + if (startNode !== 'all') { + this.onSelectNode(startNode); + } + }); + } + + selectSchema (schema) { + var s = this.state; + s['selectedSchema'] = schema; + fetch(nodeNames(schema, s['edgeFilter'])) + .then(response => response.json()) + .then(nodeNames => { + s['fromNode'] = s['toNode'] = 'none'; + s['nodeNames'] = nodeNames; + this.setState(s); + }); + fetch(validateSchema(schema)) + .then(response => response.json()) + .then(p => { + s['schemaProblems'] = p.problems; + this.setState(s); + }); + } + + changeEdgeFilter (edgeFilter) { + fetch(nodeNames(this.state.selectedSchema, edgeFilter)) + .then(response => response.json()) + .then(nodeNames => { + let s = this.state; + s['edgeFilter'] = edgeFilter; + s['fromNode'] = s['toNode'] = 'none'; + s['nodeNames'] = nodeNames; + this.setState(s); + }); + this.loadInitialGraph( + this.state.fromNode, + this.state.toNode, + this.state.hops.parents, + this.state.hops.cousin, + this.state.hops.child, + edgeFilter + ); + } + + updateHops (parentHops, cousinHops, childHops) { + this.loadInitialGraph( + this.state.fromNode, + this.state.toNode, + parentHops, + cousinHops, + childHops, + this.state.edgeFilter + ); + } + + onChangeToNode (eventKey) { + this.loadInitialGraph( + this.state.fromNode, + eventKey, + this.state.hops.parents, + this.state.hops.cousin, + this.state.hops.child, + this.state.edgeFilter + ); + } + + onSelectNode (eventKey) { + this.props.nodePropsLoader(eventKey); + } + + onChangeStartNode (eventKey) { + this.loadInitialGraph( + eventKey, + this.state.toNode, + this.state.hops.parents, + this.state.hops.cousin, + this.state.hops.child, + this.state.edgeFilter + ); + } + + componentDidMount () { + fetch(schemas()) + .then(response => response.json()) + .then(schemas => { + let s = this.state; + s['schemas'] = schemas; + this.setState(s); + }); + } + + render () { + var schemas = _.map(this.state.schemas, (x, k) => {x}); + + var items = _.map(this.state.nodeNames, (x, k) => {x.id}); + let sortedNames = _.sortBy(this.state.graph.nodeNames, 'id'); + var currentNodeNames = _.map(sortedNames, (x, k) => {x.id}); + + var fromItems = items.slice(); + fromItems.unshift(); + fromItems.unshift(all); + + items.unshift(); + items.unshift(none); + + let edgeFilterItems = [ + Edgerules, + Parent-child (OXM structure), + ]; + return ( +
+
+
+
+ + {schemas} +
+
+ + {fromItems} +
+
+ + {items} +
+
+ + {edgeFilterItems} +
+
+ + {currentNodeNames} +
+ +
+ +
+
+ +
+
+
+
+ ); + } +} + +export default GraphSettings; diff --git a/graphgraph-fe/src/graph_settings_menu.css b/graphgraph-fe/src/graph_settings_menu.css new file mode 100644 index 0000000..718dfa0 --- /dev/null +++ b/graphgraph-fe/src/graph_settings_menu.css @@ -0,0 +1,11 @@ +.navbar.navbar-adjust{ + margin-bottom: 0px; +} + +.navbar-adjust .container { + margin-left: 0; +} + +.navbar-adjust .container .navbar-header { + margin-right: 250px; +} diff --git a/graphgraph-fe/src/graph_settings_menu.js b/graphgraph-fe/src/graph_settings_menu.js new file mode 100644 index 0000000..05def48 --- /dev/null +++ b/graphgraph-fe/src/graph_settings_menu.js @@ -0,0 +1,45 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import GraphSettings from './graph_settings.js'; +import { Navbar, Nav } from 'react-bootstrap'; +import './graph_settings_menu.css'; + +class GraphSettingsMenu extends React.Component { + render () { + return ( + + + + GraphGraph + + + + + ); + } +} + +export default GraphSettingsMenu; diff --git a/graphgraph-fe/src/index.css b/graphgraph-fe/src/index.css index cee5f34..cf5eae8 100644 --- a/graphgraph-fe/src/index.css +++ b/graphgraph-fe/src/index.css @@ -1,14 +1,14 @@ body { - margin: 0; - padding: 0; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", - "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; + margin: 0; + padding: 0; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", + sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", + monospace; } diff --git a/graphgraph-fe/src/index.js b/graphgraph-fe/src/index.js index bdd3da2..4269967 100644 --- a/graphgraph-fe/src/index.js +++ b/graphgraph-fe/src/index.js @@ -1,13 +1,33 @@ -import React from 'react' -import ReactDOM from 'react-dom' -import './index.css' -import App from './App' -import * as serviceWorker from './serviceWorker' -import 'bootstrap-css-only/css/bootstrap.css' +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ -ReactDOM.render(, document.getElementById('root')) +import React from 'react'; +import ReactDOM from 'react-dom'; +import './index.css'; +import App from './app.js'; +import * as serviceWorker from './service_worker.js'; +import 'bootstrap-css-only/css/bootstrap.css'; + +ReactDOM.render(, document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: http://bit.ly/CRA-PWA -serviceWorker.unregister() +serviceWorker.unregister(); diff --git a/graphgraph-fe/src/path_breadcrumb.js b/graphgraph-fe/src/path_breadcrumb.js new file mode 100644 index 0000000..6ed9d16 --- /dev/null +++ b/graphgraph-fe/src/path_breadcrumb.js @@ -0,0 +1,46 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import _ from 'underscore'; +import React from 'react'; +import { Breadcrumb } from 'react-bootstrap'; + +class PathBreadcrumb extends React.Component { + constructor (props, context) { + super(props, context); + this.pathSelected = this.pathSelected.bind(this); + } + + pathSelected (evt) { + evt.preventDefault(); + // the data is only piggyback riding on the "target" property .. not nice but works + this.props.pathCallback(this.props.index, evt.target.getAttribute('target')); + } + + render () { + var path = this.props.path; + var callback = this.pathSelected; + var items = _.map(path, (item, i) => {item.id} ); + + return {items}; + } +} + +export default PathBreadcrumb; diff --git a/graphgraph-fe/src/popup_settings.css b/graphgraph-fe/src/popup_settings.css new file mode 100644 index 0000000..2a548af --- /dev/null +++ b/graphgraph-fe/src/popup_settings.css @@ -0,0 +1,15 @@ +.settings-button { + margin-top: 18px; + margin-left: 15px; +} + +.close.link-button { + background-color: transparent; + border: none; + cursor: pointer; + display: inline; + margin: 10px 0 0 0; + padding: 0; + text-decoration: none; + font-size: 25px; +} diff --git a/graphgraph-fe/src/popup_settings.js b/graphgraph-fe/src/popup_settings.js new file mode 100644 index 0000000..2430ab2 --- /dev/null +++ b/graphgraph-fe/src/popup_settings.js @@ -0,0 +1,40 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import Popup from 'reactjs-popup'; +import './popup_settings.css'; +import GraphHops from './graph_hops.js'; + +class PopupMenu extends React.Component { + render () { + return ( + Hops} position="bottom right"> + {close => ( +
+ + +
+ )}
+ ); + } +} + +export default PopupMenu; diff --git a/graphgraph-fe/src/requests.js b/graphgraph-fe/src/requests.js index 8a86e0c..ae41f78 100644 --- a/graphgraph-fe/src/requests.js +++ b/graphgraph-fe/src/requests.js @@ -1,35 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + const host = window.location.hostname; const port = window.location.port; const protocol = window.location.protocol; export function schemas () { - return `${protocol}//${host}:${port}/schemas` -} + return `${protocol}//${host}:${port}/schemas`; +}; export function validateSchema (schema) { - return `${protocol}//${host}:${port}/schemas/${schema}/validation` -} + return `${protocol}//${host}:${port}/schemas/${schema}/validation`; +}; export function exportSchema (schema) { - return `${protocol}//${host}:${port}/schemas/${schema}/xmiexport` -} + return `${protocol}//${host}:${port}/schemas/${schema}/xmiexport`; +}; export function nodeNames (schema, edgeFilter) { - return `${protocol}//${host}:${port}/schemas/${schema}/nodes?edgeFilter=${edgeFilter}` -} + return `${protocol}//${host}:${port}/schemas/${schema}/nodes?edgeFilter=${edgeFilter}`; +}; export function basicGraph (schema, node, parentHops, cousinHops, childHops, edgeFilter) { - return `${protocol}//${host}:${port}/schemas/${schema}/graph/basic?node=${node}&parentHops=${parentHops}&cousinHops=${cousinHops}&childHops=${childHops}&edgeFilter=${edgeFilter}` -} + return `${protocol}//${host}:${port}/schemas/${schema}/graph/basic?node=${node}&parentHops=${parentHops}&cousinHops=${cousinHops}&childHops=${childHops}&edgeFilter=${edgeFilter}`; +}; export function pathGraph (schema, fromNode, toNode, edgeFilter) { - return `${protocol}//${host}:${port}/schemas/${schema}/graph/paths?fromNode=${fromNode}&toNode=${toNode}&edgeFilter=${edgeFilter}` -} + return `${protocol}//${host}:${port}/schemas/${schema}/graph/paths?fromNode=${fromNode}&toNode=${toNode}&edgeFilter=${edgeFilter}`; +}; export function nodeProperty (schema, node) { - return `${protocol}//${host}:${port}/schemas/${schema}/nodes/${node}` -} + return `${protocol}//${host}:${port}/schemas/${schema}/nodes/${node}`; +}; export function edgeProperty (schema, fromNode, toNode) { - return `${protocol}//${host}:${port}/schemas/${schema}/edges?fromNode=${fromNode}&toNode=${toNode}` -} + return `${protocol}//${host}:${port}/schemas/${schema}/edges?fromNode=${fromNode}&toNode=${toNode}`; +}; diff --git a/graphgraph-fe/src/serviceWorker.js b/graphgraph-fe/src/serviceWorker.js deleted file mode 100644 index 5c6ead6..0000000 --- a/graphgraph-fe/src/serviceWorker.js +++ /dev/null @@ -1,135 +0,0 @@ -// This optional code is used to register a service worker. -// register() is not called by default. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the -// existing tabs open on the page have been closed, since previously cached -// resources are updated in the background. - -// To learn more about the benefits of this model and instructions on how to -// opt-in, read http://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -) - -export function register (config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href) - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config) - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit http://bit.ly/CRA-PWA' - ) - }) - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config) - } - }) - } -} - -function registerValidSW (swUrl, config) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing - if (installingWorker == null) { - return - } - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' - ) - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration) - } - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.') - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration) - } - } - } - } - } - }) - .catch(error => { - console.error('Error during service worker registration:', error) - }) -} - -function checkValidServiceWorker (swUrl, config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type') - if ( - response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload() - }) - }) - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config) - } - }) - .catch(() => { - console.log( - 'No internet connection found. App is running in offline mode.' - ) - }) -} - -export function unregister () { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister() - }) - } -} diff --git a/graphgraph-fe/src/service_worker.js b/graphgraph-fe/src/service_worker.js new file mode 100644 index 0000000..0ac740b --- /dev/null +++ b/graphgraph-fe/src/service_worker.js @@ -0,0 +1,146 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read http://bit.ly/CRA-PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.1/8 is considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) +); + +export function register (config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; + } + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; + + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit http://bit.ly/CRA-PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW (swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then(registration => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log('New content is available and will be used when all ' + + 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It's the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch(error => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker (swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl) + .then(response => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if (response.status === 404 || (contentType != null && contentType.indexOf('javascript') === -1)) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then(registration => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log('No internet connection found. App is running in offline mode.'); + }); +} + +export function unregister () { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready.then(registration => { + registration.unregister(); + }); + } +}; diff --git a/graphgraph-fe/src/validation_modal.css b/graphgraph-fe/src/validation_modal.css new file mode 100644 index 0000000..4fe12a9 --- /dev/null +++ b/graphgraph-fe/src/validation_modal.css @@ -0,0 +1,31 @@ +.modal-content +{ + height: 100%; + width: 100%; +} + +.modal-validator +{ + position: 'fixed'; + width: 1024; + height: 768; + zIndex: 1040; + top: '5%'; + left: '5%'; + border: '1px solid #e5e5e5'; + backgroundColor: 'white'; + boxShadow: '0 5px 15px rgba(0,0,0,.5)'; + padding: 0; +} + +.modal-backdrop +{ + position: 'fixed'; + zIndex: 1040; + top: 0; + bottom: 0; + left: 0; + right: 0; + backgroundColor: '#000'; + opacity: 0.5; +} diff --git a/graphgraph-fe/src/validation_modal.js b/graphgraph-fe/src/validation_modal.js new file mode 100644 index 0000000..1944c36 --- /dev/null +++ b/graphgraph-fe/src/validation_modal.js @@ -0,0 +1,58 @@ +/* + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +import _ from 'underscore'; +import React from 'react'; +import './validation_modal.css'; +import { Button, Modal, ListGroup, ListGroupItem } from 'react-bootstrap'; + +class ValidationModal extends React.Component { + constructor(...args) { + super(...args); + this.state = { showModal: false }; + this.close = () => { + this.setState({ showModal: false }); + }; + this.open = () => { + this.setState({ showModal: true }); + }; + } + + renderBackdrop(props) { + return
; + } + + render() { + var problems = this.props.schemaProblems; + var items = _.map(problems, (problem, i) => {problem}); + return ( +
+ + +
+ {items} +
+
+
+ ); + } +} + +export default ValidationModal; diff --git a/pom.xml b/pom.xml index 4c0e5cf..798a3d2 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 @@ -46,9 +46,9 @@ - ch.qos.logback - logback-classic - + ch.qos.logback + logback-classic + org.springframework.boot spring-boot-starter-web @@ -186,82 +186,82 @@ - - - com.github.eirslett - frontend-maven-plugin - 1.7.6 - - - install node - - install-node-and-npm - - generate-resources - - ${project.basedir}/graphgraph-fe - v10.10.0 - - - - npm install - - npm - - generate-resources - - ${project.basedir}/graphgraph-fe - install - - - - npm build - - npm - - generate-resources - - ${project.basedir}/graphgraph-fe - run build - - - - - - maven-resources-plugin - 3.1.0 - - - copy-resources-ui - prepare-package - - copy-resources - - - ${project.build.directory}/classes/public - - - ${project.basedir}/graphgraph-fe/build - false - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - 2.1.2.RELEASE - - - - repackage - - - - - + + + com.github.eirslett + frontend-maven-plugin + 1.7.6 + + + install node + + install-node-and-npm + + generate-resources + + ${project.basedir}/graphgraph-fe + v10.10.0 + + + + npm install + + npm + + generate-resources + + ${project.basedir}/graphgraph-fe + install + + + + npm build + + npm + + generate-resources + + ${project.basedir}/graphgraph-fe + run build + + + + + + maven-resources-plugin + 3.1.0 + + + copy-resources-ui + prepare-package + + copy-resources + + + ${project.build.directory}/classes/public + + + ${project.basedir}/graphgraph-fe/build + false + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + 2.1.2.RELEASE + + + + repackage + + + + + diff --git a/run.sh b/run.sh index 7a53739..4cfe34b 100755 --- a/run.sh +++ b/run.sh @@ -1,5 +1,5 @@ -#!/bin/sh -cd ./graphgraph-fe/ +#!/bin/sh +cd ./graphgraph-fe/ npm run build cd .. -mvn clean spring-boot:run +mvn clean spring-boot:run diff --git a/src/main/java/org/onap/aai/graphgraph/App.java b/src/main/java/org/onap/aai/graphgraph/App.java index ed1bb9a..1c6bc61 100644 --- a/src/main/java/org/onap/aai/graphgraph/App.java +++ b/src/main/java/org/onap/aai/graphgraph/App.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -40,32 +40,35 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication -public class App{ +public class App { + public static EdgeIngestor edgeIngestor; public static Map moxyLoaders = new HashMap<>(); // TODO // this should be used properly within Spring as this is a 'static' workaround due // to some initialization issues. By all means feel free to improve and move it to Spring - public static void loadSchemes(ConfigurableApplicationContext context){ + public static void loadSchemes(ConfigurableApplicationContext context) { String version; for (int i = 10; i < 19; i++) { version = "v" + i; - moxyLoaders.put(version, new MoxyLoader(new SchemaVersion(version), (NodeIngestor) context.getBean("nodeIngestor")) ); + moxyLoaders.put(version, new MoxyLoader( + new SchemaVersion(version), (NodeIngestor) context.getBean("nodeIngestor")) + ); } } - public static void main( String[] args ) throws IOException { + public static void main(String[] args) throws IOException { ArgumentParser parser = new ArgumentParser().parseArguments(args); - if (parser.isPrintHelp()){ + if (parser.isPrintHelp()) { parser.printHelp(); return; } - SpringApplication app = new SpringApplication(App.class); + SpringApplication app = new SpringApplication(App.class); - if (parser.isRunLocally()){ + if (parser.isRunLocally()) { copyKeystore(app); } @@ -74,7 +77,7 @@ public class App{ loadSchemes(context); edgeIngestor = (EdgeIngestor) context.getBean("edgeIngestor"); - if (parser.shoudGenerateUml()){ + if (parser.shouldGenerateUrl()) { writeExportedModel(exportModel(parser.getSchemaVersion())); System.exit(0); } @@ -83,9 +86,10 @@ public class App{ private static void copyKeystore(SpringApplication app) throws IOException { Path path = Paths.get("etc/auth/aai_keystore"); if (Files.notExists(path)) { - FileUtils.copyInputStreamToFile(Objects - .requireNonNull(app.getClassLoader().getResourceAsStream("etc/auth/aai_keystore")), - path.toFile()); + FileUtils.copyInputStreamToFile( + Objects.requireNonNull(app.getClassLoader().getResourceAsStream("etc/auth/aai_keystore")), + path.toFile() + ); } } } diff --git a/src/main/java/org/onap/aai/graphgraph/ArgumentParser.java b/src/main/java/org/onap/aai/graphgraph/ArgumentParser.java index 4405723..e156e39 100644 --- a/src/main/java/org/onap/aai/graphgraph/ArgumentParser.java +++ b/src/main/java/org/onap/aai/graphgraph/ArgumentParser.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -24,51 +24,50 @@ import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; public class ArgumentParser { - @Option(name = "-g", usage = "generates schema model for Papyrus and exits where XY is the version", metaVar = "vXY") - private String schemaVersion; - - @Option(name = "-d", usage = "connect to dev version of schema-service (use JAR bundled keystore)") - private boolean runLocally; - @Option(name = "-h", usage = "print help and exit") - private boolean printHelp; + CmdLineParser parser; + @Option(name = "-g", usage = "generates schema model for Papyrus and exits where XY is the version", + metaVar = "vXY") + private String schemaVersion; + @Option(name = "-d", usage = "connect to dev version of schema-service (use JAR bundled keystore)") + private boolean runLocally; + @Option(name = "-h", usage = "print help and exit") + private boolean printHelp; - CmdLineParser parser; + public ArgumentParser parseArguments(String[] args) { + parser = new CmdLineParser(this); - public ArgumentParser parseArguments(String [] args){ - parser = new CmdLineParser(this); + try { + parser.parseArgument(args); + } catch (CmdLineException e) { + System.err.println(e.getMessage()); + parser.printUsage(System.err); + } - try { - parser.parseArgument(args); - } catch( CmdLineException e ) { - System.err.println(e.getMessage()); - parser.printUsage(System.err); + return this; } - return this; - } - - public String getSchemaVersion() { - return schemaVersion; - } + public String getSchemaVersion() { + return schemaVersion; + } - public void setSchemaVersion(String schemaVersion) { - this.schemaVersion = schemaVersion; - } + public void setSchemaVersion(String schemaVersion) { + this.schemaVersion = schemaVersion; + } - public boolean shoudGenerateUml(){ - return schemaVersion != null; - } + public boolean shouldGenerateUrl() { + return schemaVersion != null; + } - public boolean isRunLocally() { - return runLocally; - } + public boolean isRunLocally() { + return runLocally; + } - public boolean isPrintHelp() { - return printHelp; - } + public boolean isPrintHelp() { + return printHelp; + } - public void printHelp(){ - parser.printUsage(System.out); - } + public void printHelp() { + parser.printUsage(System.out); + } } diff --git a/src/main/java/org/onap/aai/graphgraph/Config.java b/src/main/java/org/onap/aai/graphgraph/Config.java index 1d4152b..bbc082f 100644 --- a/src/main/java/org/onap/aai/graphgraph/Config.java +++ b/src/main/java/org/onap/aai/graphgraph/Config.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -31,9 +31,9 @@ import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages = { - "org.onap.aai.config", - "org.onap.aai.setup", - "org.onap.aai.graphgraph" + "org.onap.aai.config", + "org.onap.aai.setup", + "org.onap.aai.graphgraph" }) public class Config { @@ -41,7 +41,7 @@ public class Config { String schemaVersions; @Bean - SchemaRepository createSchemaRepository(){ + SchemaRepository createSchemaRepository() { List readers = new LinkedList<>(); for (String s : schemaVersions.split(",")) { readers.add(new BasicSchemaReader(s)); @@ -50,4 +50,3 @@ public class Config { } } - diff --git a/src/main/java/org/onap/aai/graphgraph/CorsFilter.java b/src/main/java/org/onap/aai/graphgraph/CorsFilter.java index 448a2ea..ab97255 100644 --- a/src/main/java/org/onap/aai/graphgraph/CorsFilter.java +++ b/src/main/java/org/onap/aai/graphgraph/CorsFilter.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -30,15 +30,17 @@ import org.springframework.web.filter.OncePerRequestFilter; @Component public class CorsFilter extends OncePerRequestFilter { - @Override - protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, - final FilterChain filterChain) throws ServletException, IOException { - response.addHeader("Access-Control-Allow-Origin", "*"); - response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD"); - response.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); - response.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials"); - response.addHeader("Access-Control-Allow-Credentials", "true"); - response.addIntHeader("Access-Control-Max-Age", 10); - filterChain.doFilter(request, response); - } -} \ No newline at end of file + @Override + protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, + final FilterChain filterChain) throws ServletException, IOException { + response.addHeader("Access-Control-Allow-Origin", "*"); + response.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD"); + response.addHeader("Access-Control-Allow-Headers", + "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers"); + response.addHeader("Access-Control-Expose-Headers", + "Access-Control-Allow-Origin, Access-Control-Allow-Credentials"); + response.addHeader("Access-Control-Allow-Credentials", "true"); + response.addIntHeader("Access-Control-Max-Age", 10); + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/org/onap/aai/graphgraph/ModelExporter.java b/src/main/java/org/onap/aai/graphgraph/ModelExporter.java index 36070db..047bd92 100644 --- a/src/main/java/org/onap/aai/graphgraph/ModelExporter.java +++ b/src/main/java/org/onap/aai/graphgraph/ModelExporter.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -54,214 +54,221 @@ import org.onap.aai.setup.SchemaVersion; public class ModelExporter { - private static final String AAIMODEL_UML_FILENAME = "aaimodel.uml"; - private static final String VELOCITY_TEMPLATE_FILENAME = "model_export.vm"; - private static final boolean OXM_ENABLED = false; - private static final String camelCaseRegex = "(?=[A-Z][a-z])"; - private static Map allEntities; - private static Multimap getEdgeRules(String schemaVersion) { - try { - Multimap allRules = App.edgeIngestor.getAllRules(new SchemaVersion(schemaVersion)); - allEntities = App.moxyLoaders.get(schemaVersion).getAllObjects(); - if (OXM_ENABLED) { - addOxmRelationships(allRules, allEntities); - } - return allRules; - } catch (EdgeRuleNotFoundException e) { - e.printStackTrace(); - } - - return null; - } + private static final String AAIMODEL_UML_FILENAME = "aaimodel.uml"; + private static final String VELOCITY_TEMPLATE_FILENAME = "model_export.vm"; + private static final boolean OXM_ENABLED = false; + private static final String camelCaseRegex = "(?=[A-Z][a-z])"; + private static Map allEntities; - private static void addOxmRelationships(Multimap allRules, - Map allEntities) { - for (Entry currentParent : allEntities.entrySet()) { - currentParent.getValue().getProperties().stream() - .filter(v -> allEntities.containsKey(v)) - .filter(v -> !currentParent.getKey().equals(v)) - .forEach(v -> { - String key = currentParent.getKey() + "|" + v; - if (!allRules.containsKey(key)) { - allRules.put(key, createEdgeRule(currentParent.getKey(), v)); + private static Multimap getEdgeRules(String schemaVersion) { + try { + Multimap allRules = App.edgeIngestor.getAllRules(new SchemaVersion(schemaVersion)); + allEntities = App.moxyLoaders.get(schemaVersion).getAllObjects(); + if (OXM_ENABLED) { + addOxmRelationships(allRules, allEntities); } - }); + return allRules; + } catch (EdgeRuleNotFoundException e) { + e.printStackTrace(); + } + + return null; } - } - private static EdgeRule createEdgeRule(String parent, String child) { - Map edgeRuleProps = new HashMap<>(); - edgeRuleProps.put(EdgeField.FROM.toString(), child); - edgeRuleProps.put(EdgeField.TO.toString(), parent); - edgeRuleProps.put(EdgeField.DIRECTION.toString(), Direction.OUT.toString()); //TODO check direction - edgeRuleProps.put(EdgeField.LABEL.toString(), "OXM Parent-Child"); - edgeRuleProps.put(EdgeField.MULTIPLICITY.toString(), MultiplicityRule.MANY2ONE.toString()); - edgeRuleProps.put(EdgeField.DEFAULT.toString(), Boolean.toString(false)); - edgeRuleProps.put(EdgeField.PRIVATE.toString(), Boolean.toString(false)); - edgeRuleProps.put(EdgeField.DELETE_OTHER_V.toString(), DirectionNotation.DIRECTION.toString()); - edgeRuleProps.put(EdgeField.PREVENT_DELETE.toString(), DirectionNotation.DIRECTION.toString()); - edgeRuleProps.put(EdgeField.CONTAINS.toString(), DirectionNotation.DIRECTION.toString()); - edgeRuleProps.put(EdgeField.DESCRIPTION.toString(), "fake edgerule representing parent-child"); - return new EdgeRule(edgeRuleProps); - } + private static void addOxmRelationships( + Multimap allRules, + Map allEntities) { + for (Entry currentParent : allEntities.entrySet()) { + currentParent.getValue().getProperties().stream() + .filter(v -> allEntities.containsKey(v)) + .filter(v -> !currentParent.getKey().equals(v)) + .forEach(v -> { + String key = currentParent.getKey() + "|" + v; + if (!allRules.containsKey(key)) { + allRules.put(key, createEdgeRule(currentParent.getKey(), v)); + } + }); + } + } - static String exportModel(String schemaVersion) { - Map allObjects = App.moxyLoaders.get(schemaVersion).getAllObjects(); - Template t = initVelocity(); - VelocityContext context = populateVelocityContext(schemaVersion, allObjects); - StringWriter writer = new StringWriter(); - t.merge( context, writer ); - return writer.toString(); - } + private static EdgeRule createEdgeRule(String parent, String child) { + Map edgeRuleProps = new HashMap<>(); + edgeRuleProps.put(EdgeField.FROM.toString(), child); + edgeRuleProps.put(EdgeField.TO.toString(), parent); + edgeRuleProps.put(EdgeField.DIRECTION.toString(), Direction.OUT.toString()); //TODO check direction + edgeRuleProps.put(EdgeField.LABEL.toString(), "OXM Parent-Child"); + edgeRuleProps.put(EdgeField.MULTIPLICITY.toString(), MultiplicityRule.MANY2ONE.toString()); + edgeRuleProps.put(EdgeField.DEFAULT.toString(), Boolean.toString(false)); + edgeRuleProps.put(EdgeField.PRIVATE.toString(), Boolean.toString(false)); + edgeRuleProps.put(EdgeField.DELETE_OTHER_V.toString(), DirectionNotation.DIRECTION.toString()); + edgeRuleProps.put(EdgeField.PREVENT_DELETE.toString(), DirectionNotation.DIRECTION.toString()); + edgeRuleProps.put(EdgeField.CONTAINS.toString(), DirectionNotation.DIRECTION.toString()); + edgeRuleProps.put(EdgeField.DESCRIPTION.toString(), "fake edgerule representing parent-child"); + return new EdgeRule(edgeRuleProps); + } - static void writeExportedModel(String result) { - try { - FileWriter fw = new FileWriter(AAIMODEL_UML_FILENAME); - fw.write(result); - fw.close(); - } catch (IOException e) { - e.printStackTrace(); + static String exportModel(String schemaVersion) { + Map allObjects = App.moxyLoaders.get(schemaVersion).getAllObjects(); + Template t = initVelocity(); + VelocityContext context = populateVelocityContext(schemaVersion, allObjects); + StringWriter writer = new StringWriter(); + t.merge(context, writer); + return writer.toString(); } - } - private static VelocityContext populateVelocityContext(String schemaVersion, - Map allObjects) { - VelocityContext context = new VelocityContext(); - Multimap edgeRules = getEdgeRules(schemaVersion); - Set entityList = createEntityList(edgeRules); - Set associationsList = createVelocityAssociations(entityList, edgeRules); - updateEntities(entityList, associationsList, allObjects); - context.put("entityList", entityList); - context.put("associationList", associationsList); - return context; - } + static void writeExportedModel(String result) { + try { + FileWriter fw = new FileWriter(AAIMODEL_UML_FILENAME); + fw.write(result); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } - private static Template initVelocity() { - VelocityEngine ve = new VelocityEngine(); - ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); - ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); - ve.init(); - return ve.getTemplate(VELOCITY_TEMPLATE_FILENAME); - } + private static VelocityContext populateVelocityContext( + String schemaVersion, + Map allObjects) { + VelocityContext context = new VelocityContext(); + Multimap edgeRules = getEdgeRules(schemaVersion); + Set entityList = createEntityList(edgeRules); + Set associationsList = createVelocityAssociations(entityList, edgeRules); + updateEntities(entityList, associationsList, allObjects); + context.put("entityList", entityList); + context.put("associationList", associationsList); + return context; + } - private static void updateEntities(Set entityList, - Set associationsList, - Map allObjects) { - entityList.forEach(e -> { - List associations = associationsList.stream() - .filter(a -> a.getFromEntityId().equals(e.getId())).collect( - Collectors.toList()); - updateNeighbour(entityList, associations); - String description = allEntities.get(e.getName()).getMetadata(ObjectMetadata.DESCRIPTION); - e.setDescription(StringUtil.isBlank(description) ? "no description is available" : description); - }); + private static Template initVelocity() { + VelocityEngine ve = new VelocityEngine(); + ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); + ve.init(); + return ve.getTemplate(VELOCITY_TEMPLATE_FILENAME); + } - entityList.forEach(entity -> entity.setProperties(getPropertiesForEntity(allObjects.get(entity.getName()), entityList))); + private static void updateEntities( + Set entityList, + Set associationsList, + Map allObjects) { + entityList.forEach(e -> { + List associations = associationsList.stream() + .filter(a -> a.getFromEntityId().equals(e.getId())).collect( + Collectors.toList()); + updateNeighbour(entityList, associations); + String description = allEntities.get(e.getName()).getMetadata(ObjectMetadata.DESCRIPTION); + e.setDescription(StringUtil.isBlank(description) ? "no description is available" : description); + }); - } + entityList.forEach( + entity -> entity.setProperties(getPropertiesForEntity(allObjects.get(entity.getName()), entityList))); - private static void updateNeighbour( - Set entityList, List associations) { - associations.forEach(ass -> { - VelocityEntity velocityEntity = entityList.stream() - .filter(e -> e.getId().equals(ass.getToEntityId())).findFirst().get(); - velocityEntity.addNeighbours(ass); - }); - } + } - private static Set getPropertiesForEntity(Introspector introspector, - Set entityList) { - return introspector.getProperties().stream() - .map(p -> new VelocityEntityProperty( - p, - introspector.getType(p), - findVelocityEntity(introspector.getType(p), entityList))) - .collect( - Collectors.toSet()); - } + private static void updateNeighbour( + Set entityList, List associations) { + associations.forEach(ass -> { + VelocityEntity velocityEntity = entityList.stream() + .filter(e -> e.getId().equals(ass.getToEntityId())).findFirst().get(); + velocityEntity.addNeighbours(ass); + }); + } - private static Set createEntityList( - Multimap edgeRules) { - return Objects.requireNonNull(edgeRules).values().stream() - .flatMap(er -> Stream.of(er.getFrom(), er.getTo())) - .map(VelocityEntity::new) - .collect(Collectors.toSet()); - } + private static Set getPropertiesForEntity( + Introspector introspector, + Set entityList) { + return introspector.getProperties().stream() + .map(p -> new VelocityEntityProperty( + p, + introspector.getType(p), + findVelocityEntity(introspector.getType(p), entityList))) + .collect( + Collectors.toSet()); + } - private static Set createVelocityAssociations(Set entities, - Multimap edgeRules) { - return edgeRules.values().stream().flatMap(er -> { - VelocityAssociation out = createVelocityAssociation(entities, er.getFrom(), er.getTo(), - er.getLabel(), er.getMultiplicityRule().name(), er.getContains()); - VelocityAssociation in = createVelocityAssociation(entities, er.getTo(), er.getFrom(), - er.getLabel(), er.getMultiplicityRule().name(), er.getContains()); - switch (er.getDirection()) { - case OUT: - return Stream.of(out); - case IN: - return Stream.of(in); - case BOTH: - return Stream.of(out, in); - default: - return null; - } - }).collect(Collectors.toSet()); - } + private static Set createEntityList( + Multimap edgeRules) { + return Objects.requireNonNull(edgeRules).values().stream() + .flatMap(er -> Stream.of(er.getFrom(), er.getTo())) + .map(VelocityEntity::new) + .collect(Collectors.toSet()); + } - private static VelocityAssociation createVelocityAssociation(Set entities, - String from, String to, String label, String multiplicity, String contains) { - VelocityEntity fromEntity = entities.stream().filter(ent -> ent.getName().equals(from)) - .findFirst().get(); - VelocityEntity toEntity = entities.stream().filter(ent -> ent.getName().equals(to)).findFirst() - .get(); - switch (contains) { - case "IN": - return new VelocityAssociation( - fromEntity, - toEntity, - String.format("%s - %s (%s)", from, to, shortenLabel(label)), - multiplicity, - true); - case "OUT": - return new VelocityAssociation( - toEntity, - fromEntity, - String.format("%s - %s (%s)", to, from, shortenLabel(label)), - multiplicity.equals("ONE2MANY") ? "MANY2ONE" : multiplicity, - true); - default: - return new VelocityAssociation( - fromEntity, - toEntity, - String.format("%s - %s (%s)", from, to, shortenLabel(label)), - multiplicity, - false); + private static Set createVelocityAssociations( + Set entities, + Multimap edgeRules) { + return edgeRules.values().stream().flatMap(er -> { + VelocityAssociation out = createVelocityAssociation(entities, er.getFrom(), er.getTo(), + er.getLabel(), er.getMultiplicityRule().name(), er.getContains()); + VelocityAssociation in = createVelocityAssociation(entities, er.getTo(), er.getFrom(), + er.getLabel(), er.getMultiplicityRule().name(), er.getContains()); + switch (er.getDirection()) { + case OUT: + return Stream.of(out); + case IN: + return Stream.of(in); + case BOTH: + return Stream.of(out, in); + default: + return null; + } + }).collect(Collectors.toSet()); } - } - private static String shortenLabel(String label) { - if (label.contains(".")) { - String[] split = label.split("\\."); - return split[split.length - 1]; + private static VelocityAssociation createVelocityAssociation( + Set entities, String from, String to, String label, String multiplicity, String contains) { + VelocityEntity fromEntity = entities.stream() + .filter(ent -> ent.getName().equals(from)).findFirst().get(); + VelocityEntity toEntity = entities.stream() + .filter(ent -> ent.getName().equals(to)).findFirst().get(); + switch (contains) { + case "IN": + return new VelocityAssociation( + fromEntity, + toEntity, + String.format("%s - %s (%s)", from, to, shortenLabel(label)), + multiplicity, + true); + case "OUT": + return new VelocityAssociation( + toEntity, + fromEntity, + String.format("%s - %s (%s)", to, from, shortenLabel(label)), + multiplicity.equals("ONE2MANY") ? "MANY2ONE" : multiplicity, + true); + default: + return new VelocityAssociation( + fromEntity, + toEntity, + String.format("%s - %s (%s)", from, to, shortenLabel(label)), + multiplicity, + false); + } } - return label; - } + private static String shortenLabel(String label) { + if (label.contains(".")) { + String[] split = label.split("\\."); + return split[split.length - 1]; + } - private static VelocityEntity findVelocityEntity(String entityName, Set entities) { - if (entityName.startsWith("java.lang")){ - return null; + return label; } - if ( ! entityName.startsWith("inventory.aai.onap.org")){ - return null; - } + private static VelocityEntity findVelocityEntity(String entityName, Set entities) { + if (entityName.startsWith("java.lang")) { + return null; + } - String[] split = entityName.split("\\."); - String entityNameRoot = split[split.length - 1]; - final Pattern pattern = Pattern.compile(camelCaseRegex); - final Matcher matcher = pattern.matcher(entityNameRoot.substring(1, entityNameRoot.length())); - String finalEntityNameRoot = (entityNameRoot.charAt(0) + matcher.replaceAll("-")).toLowerCase(); - return entities.stream().filter(e -> e.getName().equals(finalEntityNameRoot)).findFirst().orElse(null); - } -} \ No newline at end of file + if (!entityName.startsWith("inventory.aai.onap.org")) { + return null; + } + + String[] split = entityName.split("\\."); + String entityNameRoot = split[split.length - 1]; + final Pattern pattern = Pattern.compile(camelCaseRegex); + final Matcher matcher = pattern.matcher(entityNameRoot.substring(1)); + String finalEntityNameRoot = (entityNameRoot.charAt(0) + matcher.replaceAll("-")).toLowerCase(); + return entities.stream().filter(e -> e.getName().equals(finalEntityNameRoot)).findFirst().orElse(null); + } +} diff --git a/src/main/java/org/onap/aai/graphgraph/SchemaResource.java b/src/main/java/org/onap/aai/graphgraph/SchemaResource.java index b38ef7b..577e235 100644 --- a/src/main/java/org/onap/aai/graphgraph/SchemaResource.java +++ b/src/main/java/org/onap/aai/graphgraph/SchemaResource.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -43,67 +43,66 @@ public class SchemaResource { SchemaRepository repository; @RequestMapping("/schemas") - public List loadSchemaNames() { + public List loadSchemaNames() { return repository.getAllSchemaNames(); } - @RequestMapping("/schemas/{schema}/nodes") - public List loadVertexNames(@PathVariable("schema") String schemaName, - @RequestParam("edgeFilter") String edgeFilter) { + public List loadVertexNames( + @PathVariable("schema") String schemaName, + @RequestParam("edgeFilter") String edgeFilter) { return repository.getSchemaReader(schemaName).getAllVertexNames(edgeFilter); } @RequestMapping("/schemas/{schema}/nodes/{node}") - public List loadProperties(@PathVariable("schema") String schemaName, @PathVariable("node") String node) { + public List loadProperties( + @PathVariable("schema") String schemaName, + @PathVariable("node") String node) { return repository.getSchemaReader(schemaName).getVertexProperties(node); } - @RequestMapping("/schemas/{schema}/edges") - public List loadedgeProperties ( + public List loadEdgeProperties( @PathVariable("schema") String schemaName, @RequestParam("fromNode") String fromNodeName, @RequestParam("toNode") String toNodeName) { return repository.getSchemaReader(schemaName).getEdgeProperties(fromNodeName, toNodeName, "edgerule"); } - @RequestMapping("/schemas/{schema}/graph/basic") - public Graph loadGraph ( + public Graph loadGraph( @PathVariable("schema") String schemaName, @RequestParam("node") String initialNodeName, @RequestParam("parentHops") Integer parentHops, @RequestParam("cousinHops") Integer cousinHops, @RequestParam("childHops") Integer childHops, - @RequestParam("edgeFilter") String edgeFilter) - { - Graph graph = repository.getSchemaReader(schemaName).getGraph(initialNodeName, parentHops, cousinHops, childHops, edgeFilter); - graph.setPaths(Collections.emptyList()); - return graph; + @RequestParam("edgeFilter") String edgeFilter) { + Graph graph = repository.getSchemaReader(schemaName) + .getGraph(initialNodeName, parentHops, cousinHops, childHops, edgeFilter); + graph.setPaths(Collections.emptyList()); + return graph; } - @RequestMapping("/schemas/{schema}/graph/paths") - public Graph loadGraphWithPaths ( + public Graph loadGraphWithPaths( @PathVariable("schema") String schemaName, @RequestParam("fromNode") String fromNode, @RequestParam("toNode") String toNode, - @RequestParam("edgeFilter") String edgeFilter) - { + @RequestParam("edgeFilter") String edgeFilter) { return repository.getSchemaReader(schemaName).getGraph(fromNode, toNode, edgeFilter); } @RequestMapping("/schemas/{schema}/validation") - public ValidationProblems validateSchema ( @PathVariable("schema") String schemaName) { + public ValidationProblems validateSchema( + @PathVariable("schema") String schemaName) { return new SchemaValidator().validate(schemaName); } @RequestMapping(value = "/schemas/{schema}/xmiexport", produces = MediaType.TEXT_XML_VALUE) @ResponseBody - public String exportSchema ( @PathVariable("schema") String schemaName) { + public String exportSchema( + @PathVariable("schema") String schemaName) { return ModelExporter.exportModel(schemaName); } } - diff --git a/src/main/java/org/onap/aai/graphgraph/SchemaValidator.java b/src/main/java/org/onap/aai/graphgraph/SchemaValidator.java index aa260aa..076c31e 100644 --- a/src/main/java/org/onap/aai/graphgraph/SchemaValidator.java +++ b/src/main/java/org/onap/aai/graphgraph/SchemaValidator.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -32,70 +32,74 @@ import org.onap.aai.graphgraph.dto.ValidationProblems; import org.onap.aai.graphgraph.reader.BasicSchemaReader; public class SchemaValidator { - private Graph edgerules; - private Graph oxm; - public ValidationProblems validate(String schemaVersion) { - ValidationProblems validationProblems = new ValidationProblems(); - BasicSchemaReader schema = new BasicSchemaReader(schemaVersion); - oxm = schema.getGraph("all", 0, 0, 0, "Parents"); - edgerules = schema.getGraph("all", 0, 0, 0, "Edgerules"); - checkIfDanglingEdgerules(validationProblems); - checkIfObsoleteOxm(validationProblems); - schema.getSchemaErrors().forEach(validationProblems::addProblem); - return validationProblems; - } + private Graph edgerules; + private Graph oxm; + + public ValidationProblems validate(String schemaVersion) { + ValidationProblems validationProblems = new ValidationProblems(); + BasicSchemaReader schema = new BasicSchemaReader(schemaVersion); + oxm = schema.getGraph("all", 0, 0, 0, "Parents"); + edgerules = schema.getGraph("all", 0, 0, 0, "Edgerules"); + + checkIfDanglingEdgerules(validationProblems); + checkIfObsoleteOxm(validationProblems); + schema.getSchemaErrors().forEach(validationProblems::addProblem); + return validationProblems; + } - /** - * computes nodes connected to relationship-list but not used in edgerules - * @param validationProblems - */ - private void checkIfObsoleteOxm(ValidationProblems validationProblems) { - Set relationshipListConnected = getAllNodesConnectedToRelationshipList(); - Set nodesInEdgerules = getEdgerulePairs().stream().flatMap(p -> Stream.of(p._1, p._2)) - .collect(Collectors.toSet()); - relationshipListConnected.removeAll(nodesInEdgerules); - relationshipListConnected.forEach(n -> - validationProblems.addProblem(String.format("%s is associated with relationship-list in OXM but not present in edgerules", n))); - } + /** + * computes nodes connected to relationship-list but not used in edgerules + * @param validationProblems + */ + private void checkIfObsoleteOxm(ValidationProblems validationProblems) { + Set relationshipListConnected = getAllNodesConnectedToRelationshipList(); + Set nodesInEdgerules = getEdgerulePairs().stream() + .flatMap(p -> Stream.of(p._1, p._2)) + .collect(Collectors.toSet()); + relationshipListConnected.removeAll(nodesInEdgerules); + relationshipListConnected.forEach(n -> validationProblems.addProblem( + String.format("%s is associated with relationship-list in OXM but not present in edgerules", + n))); + } - private Set> getEdgerulePairs() { - return edgerules.getEdges().stream() - .map(e -> Tuple.of(e.getSource(), e.getTarget())).collect( - Collectors.toSet()); - } + private Set> getEdgerulePairs() { + return edgerules.getEdges().stream() + .map(e -> Tuple.of(e.getSource(), e.getTarget())) + .collect(Collectors.toSet()); + } - /** - * computes edgerules which don't have the necessary connection to relationship-list in OXM - * @param validationProblems - */ - private void checkIfDanglingEdgerules( - ValidationProblems validationProblems) { - Set> edgerulePairs = getEdgerulePairs(); - edgerulePairs.removeAll(getOxmPairs()); - edgerulePairs.forEach( erp -> - validationProblems.addProblem(String.format("%s and %s are associated in edgerules but not in OXM (via relationship-list)", erp._1, erp._2))); - } + /** + * computes edgerules which don't have the necessary connection to relationship-list in OXM + * @param validationProblems + */ + private void checkIfDanglingEdgerules(ValidationProblems validationProblems) { + Set> edgerulePairs = getEdgerulePairs(); + edgerulePairs.removeAll(getOxmPairs()); + edgerulePairs.forEach(erp -> validationProblems.addProblem( + String.format("%s and %s are associated in edgerules but not in OXM (via relationship-list)", + erp._1, erp._2))); + } - private Set> getOxmPairs() { - Set> pairs = new HashSet<>(); - Set inRelationshipList = getAllNodesConnectedToRelationshipList(); + private Set> getOxmPairs() { + Set> pairs = new HashSet<>(); + Set inRelationshipList = getAllNodesConnectedToRelationshipList(); - inRelationshipList.forEach(edge1 -> - inRelationshipList.forEach(edge2 -> { - pairs.add(Tuple.of(edge1, edge2)); - })); - return pairs; - } + inRelationshipList.forEach(edge1 -> inRelationshipList + .forEach(edge2 -> pairs.add(Tuple.of(edge1, edge2)))); + return pairs; + } - private Set getAllNodesConnectedToRelationshipList() { - List edges = oxm.getEdges(); - Set inRelationshipList = edges.stream().filter(e -> e.getSource().equals("relationship-list")).map( - Edge::getTarget).collect( - Collectors.toSet()); - inRelationshipList.addAll(edges.stream().filter(e -> e.getTarget().equals("relationship-list")) - .map(Edge::getSource).collect( - Collectors.toSet())); - return inRelationshipList; - } + private Set getAllNodesConnectedToRelationshipList() { + List edges = oxm.getEdges(); + Set inRelationshipList = edges.stream() + .filter(e -> e.getSource().equals("relationship-list")) + .map(Edge::getTarget) + .collect(Collectors.toSet()); + inRelationshipList.addAll(edges.stream() + .filter(e -> e.getTarget().equals("relationship-list")) + .map(Edge::getSource) + .collect(Collectors.toSet())); + return inRelationshipList; + } } diff --git a/src/main/java/org/onap/aai/graphgraph/dto/Edge.java b/src/main/java/org/onap/aai/graphgraph/dto/Edge.java index 5154e5b..c3ba8df 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/Edge.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/Edge.java @@ -1,26 +1,25 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; import java.util.Arrays; -import java.util.Collections; import java.util.List; public class Edge { @@ -49,14 +48,14 @@ public class Edge { return source; } - public List getNodeNames() { - return Arrays.asList(new NodeName(source), new NodeName(target)); - } - public void setSource(String source) { this.source = source; } + public List getNodeNames() { + return Arrays.asList(new NodeName(source), new NodeName(target)); + } + public String getTarget() { return target; } diff --git a/src/main/java/org/onap/aai/graphgraph/dto/Graph.java b/src/main/java/org/onap/aai/graphgraph/dto/Graph.java index 83e5977..7d5f957 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/Graph.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/Graph.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; @@ -23,12 +23,15 @@ import java.util.Collections; import java.util.List; public class Graph { + private List nodeNames; private List edges; private List> paths; private List startNodeProperties; - public Graph(List nodeNames, List edges, List> pathsList, List startNodeProperties) { + public Graph( + List nodeNames, List edges, + List> pathsList, List startNodeProperties) { this.nodeNames = nodeNames; this.edges = edges; this.paths = pathsList; @@ -36,8 +39,8 @@ public class Graph { } public static Graph emptyGraph() { - return new Graph(Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), - Collections.emptyList()); + return new Graph( + Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList()); } public List getStartNodeProperties() { diff --git a/src/main/java/org/onap/aai/graphgraph/dto/NodeName.java b/src/main/java/org/onap/aai/graphgraph/dto/NodeName.java index 992609c..013f1aa 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/NodeName.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/NodeName.java @@ -1,25 +1,26 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; public class NodeName { + private String id; public NodeName(String name) { @@ -56,8 +57,6 @@ public class NodeName { @Override public String toString() { - return "NodeName{" + - "id='" + id + '\'' + - '}'; + return "NodeName{" + "id='" + id + '\'' + '}'; } } diff --git a/src/main/java/org/onap/aai/graphgraph/dto/NodeProperty.java b/src/main/java/org/onap/aai/graphgraph/dto/NodeProperty.java index 93b04cf..0daa9f4 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/NodeProperty.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/NodeProperty.java @@ -1,33 +1,35 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; public class NodeProperty extends Property { + private String description; private String type; private boolean key; private boolean index; private boolean required; - public NodeProperty(String propertyName, - String description, String type, boolean key, boolean index, boolean required) { + public NodeProperty( + String propertyName, String description, String type, + boolean key, boolean index, boolean required) { super(propertyName, ""); this.description = description; this.type = type; @@ -92,7 +94,7 @@ public class NodeProperty extends Property { @Override public int hashCode() { - return getPropertyName().hashCode(); + return getPropertyName().hashCode(); } @Override diff --git a/src/main/java/org/onap/aai/graphgraph/dto/Property.java b/src/main/java/org/onap/aai/graphgraph/dto/Property.java index add7dc1..a08b0ec 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/Property.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/Property.java @@ -1,25 +1,26 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; -public class Property implements Comparable{ +public class Property implements Comparable { + private String propertyName; private String propertyValue; @@ -59,7 +60,6 @@ public class Property implements Comparable{ return false; } return propertyValue.equals(property.propertyValue); - } @Override @@ -71,8 +71,8 @@ public class Property implements Comparable{ @Override public int compareTo(Property o) { - if (o.getPropertyName().equals(getPropertyName()) && o.getPropertyValue() != null - && getPropertyValue() != null) { + if (o.getPropertyName().equals(getPropertyName()) + && o.getPropertyValue() != null && getPropertyValue() != null) { return getPropertyValue().compareTo(o.getPropertyValue()); } diff --git a/src/main/java/org/onap/aai/graphgraph/dto/ValidationProblems.java b/src/main/java/org/onap/aai/graphgraph/dto/ValidationProblems.java index 9b031d0..976058d 100644 --- a/src/main/java/org/onap/aai/graphgraph/dto/ValidationProblems.java +++ b/src/main/java/org/onap/aai/graphgraph/dto/ValidationProblems.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.dto; @@ -23,17 +23,18 @@ import java.util.LinkedList; import java.util.List; public class ValidationProblems { + private List problems = new LinkedList<>(); - public List getProblems() { - return problems; - } + public List getProblems() { + return problems; + } - public void setProblems(List problems) { - this.problems = problems; - } + public void setProblems(List problems) { + this.problems = problems; + } - public void addProblem(String problem) { - problems.add(problem); - } + public void addProblem(String problem) { + problems.add(problem); + } } diff --git a/src/main/java/org/onap/aai/graphgraph/reader/BasicSchemaReader.java b/src/main/java/org/onap/aai/graphgraph/reader/BasicSchemaReader.java index b2d766b..7f903f7 100644 --- a/src/main/java/org/onap/aai/graphgraph/reader/BasicSchemaReader.java +++ b/src/main/java/org/onap/aai/graphgraph/reader/BasicSchemaReader.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.reader; @@ -50,357 +50,356 @@ import org.onap.aai.setup.SchemaVersion; public class BasicSchemaReader implements SchemaReader { - private Map allEntities; - private Graph graph = new DefaultDirectedGraph<>(MetadataEdge.class); - private EdgeIngestor edgeIngestor; - private String version; - private List schemaErrors = new LinkedList<>(); + private Map allEntities; + private Graph graph = new DefaultDirectedGraph<>(MetadataEdge.class); + private EdgeIngestor edgeIngestor; + private String version; + private List schemaErrors = new LinkedList<>(); - public List getSchemaErrors() { - return schemaErrors; - } + public BasicSchemaReader(String version) { + this.version = version; + } - public BasicSchemaReader(String version) { - this.version = version; - } + public List getSchemaErrors() { + return schemaErrors; + } - private void init() { - if (allEntities != null) { - return; + private void init() { + if (allEntities != null) { + return; + } + allEntities = App.moxyLoaders.get(getSchemaName()).getAllObjects(); + edgeIngestor = App.edgeIngestor; + graph = createGraph(true, true); } - allEntities = App.moxyLoaders.get(getSchemaName()).getAllObjects(); - edgeIngestor = App.edgeIngestor; - graph = createGraph(true, true); - } - - private Graph createGraph(boolean withParentChild, boolean withEdgeRules) { - Graph graph = new DefaultDirectedGraph<>(MetadataEdge.class); - for (Entry currentParent : allEntities.entrySet()) { - graph.addVertex(currentParent.getKey()); - currentParent.getValue().getProperties().stream() - .filter(v -> allEntities.containsKey(v)) - .filter(v -> !currentParent.getKey().equals(v)) - .forEach(v -> { - graph.addVertex(v); - if (withParentChild) { - addParentChildEdge(currentParent.getKey(), v, graph); - } - }); + + private Graph createGraph(boolean withParentChild, boolean withEdgeRules) { + Graph graph = new DefaultDirectedGraph<>(MetadataEdge.class); + for (Entry currentParent : allEntities.entrySet()) { + graph.addVertex(currentParent.getKey()); + currentParent.getValue().getProperties().stream() + .filter(v -> allEntities.containsKey(v)) + .filter(v -> !currentParent.getKey().equals(v)) + .forEach(v -> { + graph.addVertex(v); + if (withParentChild) { + addParentChildEdge(currentParent.getKey(), v, graph); + } + }); + } + + if (!withEdgeRules) { + return graph; + } + + Multimap allRules = null; + try { + allRules = edgeIngestor.getAllRules(new SchemaVersion(getSchemaName())); + } catch (EdgeRuleNotFoundException e) { + //TODO fix + } + + allRules.asMap().values().stream() + .flatMap(e -> e.stream()) + .forEach(e -> { + switch (e.getDirection()) { + case OUT: + addEdgerule(e.getFrom(), e.getTo(), e.getLabel(), graph); + break; + case IN: + addEdgerule(e.getTo(), e.getFrom(), e.getLabel(), graph); + break; + case BOTH: + addEdgerule(e.getFrom(), e.getTo(), e.getLabel(), graph); + addEdgerule(e.getTo(), e.getFrom(), e.getLabel(), graph); + break; + } + }); + + return graph; + } + + private void addEdgerule(String parent, String child, String label, Graph graph) { + //shortening labels, long edge names are unreadable in the UI + if (label.contains(".")) { + String[] split = label.split("\\."); + label = split[split.length - 1]; + } + checkVertexExist(graph, parent); + checkVertexExist(graph, child); + + graph.addEdge(child, parent, + new MetadataEdge(EdgeType.EDGE_RULE.getTypeName(), child, parent, label)); + } + + private void checkVertexExist(Graph graph, String vertex) { + if (!graph.vertexSet().contains(vertex)) { + graph.addVertex(vertex); + schemaErrors.add(String.format("Schema is inconsistent, missing node %s", vertex)); + } + } + + private void addParentChildEdge(String parent, String child, Graph graph) { + graph.addEdge(parent, child, + new MetadataEdge(EdgeType.PARENT.getTypeName(), parent, child, EdgeType.PARENT.getTypeName())); + graph.addEdge(child, parent, + new MetadataEdge(EdgeType.CHILD.getTypeName(), child, parent, EdgeType.CHILD.getTypeName())); + } + + @Override + public String getSchemaName() { + return version; + } + + @Override + public List getAllVertexNames(String edgeFilter) { + init(); + + return createGraph( + isParentChildFilter(edgeFilter), + isEdgeRulesFilter(edgeFilter)).edgeSet().stream() + .flatMap(e -> Arrays.asList(e.getSource(), e.getTarget()).stream()) + .sorted().distinct() + .map(NodeName::new) + .collect(Collectors.toList()); } - if (!withEdgeRules) { - return graph; + @Override + public List getVertexProperties(String nodeName) { + init(); + + if (!allEntities.containsKey(nodeName)) { + return Collections.emptyList(); + } + Introspector introspector = allEntities.get(nodeName); + List properties = introspector.getProperties().stream().sorted().collect(Collectors.toList()); + + return properties.stream() + .map(p -> new NodeProperty( + p, + introspector.getPropertyMetadata(p).getOrDefault( + PropertyMetadata.DESCRIPTION, "no description available"), + introspector.getType(p), + introspector.getAllKeys().contains(p), + introspector.getIndexedProperties().contains(p), + introspector.getRequiredProperties().contains(p))) + .collect(Collectors.toList()); + } + + @Override + public List getEdgeProperties(String fromNode, String toNode, String type) { + init(); + if (type.equals(EdgeType.EDGE_RULE.getTypeName())) { + try { + List rules = edgeIngestor.getAllRules(new SchemaVersion(getSchemaName())) + .asMap().values().stream() + .flatMap(Collection::stream) + .filter(identifyEdgeRule(fromNode, toNode)) + .collect(Collectors.toList()); + + Optional> properties = rules.stream().map(this::edgeRuleProperties).findFirst(); + return properties.orElse(Collections.emptyList()); + + } catch (EdgeRuleNotFoundException e) { + //TODO fix + } + } + return Collections.emptyList(); } - Multimap allRules = null; - try { - allRules = edgeIngestor.getAllRules(new SchemaVersion(getSchemaName())); - } catch (EdgeRuleNotFoundException e) { - //TODO fix + private Predicate identifyEdgeRule(String fromNode, String toNode) { + return e -> { + switch (e.getDirection()) { + case OUT: + return e.getFrom().equals(fromNode) && e.getTo().equals(toNode); + case IN: + return e.getFrom().equals(toNode) && e.getTo().equals(fromNode); + case BOTH: + return e.getFrom().equals(toNode) && e.getTo().equals(fromNode) + || e.getFrom().equals(fromNode) && e.getTo().equals(toNode); + default: + return false; + } + }; } - allRules.asMap().values().stream().flatMap(e -> e.stream()).forEach(e -> { - switch (e.getDirection()) { - case OUT: - addEdgerule(e.getFrom(), e.getTo(), e.getLabel(), graph); - break; - case IN: - addEdgerule(e.getTo(), e.getFrom(), e.getLabel(), graph); - break; - case BOTH: - addEdgerule(e.getFrom(), e.getTo(), e.getLabel(), graph); - addEdgerule(e.getTo(), e.getFrom(), e.getLabel(), graph); - break; - } - }); - - return graph; - } - - private void addEdgerule(String parent, String child, String label, - Graph graph) { - //shortening labels, long edge names are unreadable in the UI - if (label.contains(".")) { - String[] split = label.split("\\."); - label = split[split.length - 1]; + private List edgeRuleProperties(EdgeRule r) { + List ps = new LinkedList<>(); + ps.add(new Property("Multiplicity", r.getMultiplicityRule().name())); + ps.add(new Property("Is default edge", String.valueOf(r.isDefault()))); + ps.add(new Property("Description", r.getDescription())); + ps.add(new Property("Is private edge", String.valueOf(r.isPrivateEdge()))); + ps.add(new Property("Contains", r.getContains())); + ps.add(new Property("Prevent delete", r.getPreventDelete())); + ps.add(new Property("Label", r.getLabel())); + ps.add(new Property("Delete other v", r.getDeleteOtherV())); + return ps; } - checkVertexExist(graph, parent); - checkVertexExist(graph, child); - graph.addEdge(child, parent, - new MetadataEdge(EdgeType.EDGE_RULE.getTypeName(), child, parent, label)); - } + @Override + public org.onap.aai.graphgraph.dto.Graph getGraph( + String initialNode, int parentHops, int cousinHops, int childHops, String edgeFilter) { + init(); + + Optional anyVertex = graph.vertexSet().stream().findFirst(); + if (!anyVertex.isPresent()) { + return org.onap.aai.graphgraph.dto.Graph.emptyGraph(); + } + Set edges = computeAllEdges( + anyVertex.get(), isParentChildFilter(edgeFilter), isEdgeRulesFilter(edgeFilter)); + + if (!"all".equals(initialNode)) { + Set subGraphVertices = computeNodes(initialNode, parentHops, EdgeType.CHILD.getTypeName()); + subGraphVertices.addAll(computeNodes(initialNode, childHops, EdgeType.PARENT.getTypeName())); + subGraphVertices.addAll(computeNodes(initialNode, cousinHops, EdgeType.EDGE_RULE.getTypeName())); + edges = filterEdges(edges, subGraphVertices); + } - private void checkVertexExist(Graph graph, String vertex) { - if (! graph.vertexSet().contains(vertex)) { - graph.addVertex(vertex); - schemaErrors.add(String.format("Schema is inconsistent, missing node %s", vertex)); + return new org.onap.aai.graphgraph.dto.Graph(new LinkedList<>(computeNodeNames(edges)), + new LinkedList<>(edges), Collections.emptyList(), getVertexProperties(initialNode)); } - } - - private void addParentChildEdge(String parent, String child, Graph graph) { - graph.addEdge(parent, child, - new MetadataEdge(EdgeType.PARENT.getTypeName(), parent, child, EdgeType.PARENT.getTypeName())); - graph.addEdge(child, parent, - new MetadataEdge(EdgeType.CHILD.getTypeName(), child, parent, EdgeType.CHILD.getTypeName())); - } - - @Override - public String getSchemaName() { - return version; - } - - @Override - public List getAllVertexNames(String edgeFilter) { - init(); - - return createGraph(isParentChildFilter(edgeFilter), isEdgeRulesFilter(edgeFilter)) - .edgeSet().stream().flatMap(e -> Arrays.asList(e.getSource(), e.getTarget()).stream()) - .sorted() - .distinct() - .map(NodeName::new).collect( - Collectors.toList()); - } - - @Override - public List getVertexProperties(String nodeName) { - init(); - - if (!allEntities.containsKey(nodeName)) { - return Collections.emptyList(); + + private boolean isParentChildFilter(String edgeFilter) { + return "Parents".equals(edgeFilter); } - Introspector introspector = allEntities.get(nodeName); - List properties = introspector.getProperties().stream() - .sorted() - .collect(Collectors.toList()); - - List result = properties.stream().map( p -> - new NodeProperty( - p, - introspector.getPropertyMetadata(p) - .getOrDefault(PropertyMetadata.DESCRIPTION,"no description available"), - introspector.getType(p), - introspector.getAllKeys().contains(p), - introspector.getIndexedProperties().contains(p), - introspector.getRequiredProperties().contains(p)) - ).collect(Collectors.toList()); - - return result; - } - - @Override - public List getEdgeProperties(String fromNode, String toNode, String type) { - init(); - if (type.equals(EdgeType.EDGE_RULE.getTypeName())) { - try { - List rules = edgeIngestor.getAllRules(new SchemaVersion(getSchemaName())) - .asMap() - .values() - .stream() - .flatMap(Collection::stream) - .filter(identifyEdgeRule(fromNode, toNode)) - .collect(Collectors.toList()); - - Optional> properties = rules.stream().map(this::edgeRuleProperties) - .findFirst(); - return properties.orElse(Collections.emptyList()); - - } catch (EdgeRuleNotFoundException e) { - //TODO fix - } + private boolean isEdgeRulesFilter(String edgeFilter) { + return "Edgerules".equals(edgeFilter); } - return Collections.emptyList(); - } - - private Predicate identifyEdgeRule(String fromNode, String toNode) { - return e -> { - switch (e.getDirection()) { - case OUT: - return e.getFrom().equals(fromNode) && e.getTo().equals(toNode); - case IN: - return e.getFrom().equals(toNode) && e.getTo().equals(fromNode); - case BOTH: - return e.getFrom().equals(toNode) && e.getTo().equals(fromNode) - || e.getFrom().equals(fromNode) && e.getTo().equals(toNode); - default: - return false; - } - }; - } - - private List edgeRuleProperties(EdgeRule r) { - List ps = new LinkedList<>(); - ps.add(new Property("Multiplicity", r.getMultiplicityRule().name())); - ps.add(new Property("Is default edge", String.valueOf(r.isDefault()))); - ps.add(new Property("Description", r.getDescription())); - ps.add(new Property("Is private edge", String.valueOf(r.isPrivateEdge()))); - ps.add(new Property("Contains", r.getContains())); - ps.add(new Property("Prevent delete", r.getPreventDelete())); - ps.add(new Property("Label", r.getLabel())); - ps.add(new Property("Delete other v", r.getDeleteOtherV())); - return ps; - } - - @Override - public org.onap.aai.graphgraph.dto.Graph getGraph(String initialNode, int parentHops, - int cousinHops, int childHops, String edgeFilter) { - init(); - - Optional anyVertex = graph.vertexSet().stream().findFirst(); - if (!anyVertex.isPresent()) { - return org.onap.aai.graphgraph.dto.Graph.emptyGraph(); + + private Set filterEdgesStrict(Set edges, Set subGraphVertices) { + return edges.stream() + .filter(e -> subGraphVertices.contains(e.getSource()) && subGraphVertices.contains(e.getTarget())) + .collect(Collectors.toSet()); } - Set edges = computeAllEdges(anyVertex.get(), isParentChildFilter(edgeFilter), - isEdgeRulesFilter(edgeFilter)); - - if (!"all".equals(initialNode)) { - Set subGraphVertices = computeNodes(initialNode, parentHops, EdgeType.CHILD.getTypeName()); - subGraphVertices.addAll(computeNodes(initialNode, childHops, EdgeType.PARENT.getTypeName())); - subGraphVertices.addAll(computeNodes(initialNode, cousinHops, EdgeType.EDGE_RULE.getTypeName())); - edges = filterEdges(edges, subGraphVertices); + + private Set filterEdges(Set edges, Set subGraphVertices) { + return edges.stream() + .filter(e -> subGraphVertices.contains(e.getSource()) || subGraphVertices.contains(e.getTarget())) + .filter(e -> !e.getType().equals(EdgeType.EDGE_RULE.getTypeName())) + .collect(Collectors.toSet()); } - return new org.onap.aai.graphgraph.dto.Graph(new LinkedList<>(computeNodeNames(edges)), - new LinkedList<>(edges), Collections.emptyList(), getVertexProperties(initialNode)); - } - - private boolean isParentChildFilter(String edgeFilter) { - return "Parents".equals(edgeFilter); - } - - private boolean isEdgeRulesFilter(String edgeFilter) { - return "Edgerules".equals(edgeFilter); - } - - private Set filterEdgesStrict(Set edges, Set subGraphVertices) { - return edges.stream().filter( - e -> subGraphVertices.contains(e.getSource()) && subGraphVertices.contains(e.getTarget())) - .collect( - Collectors.toSet()); - } - - private Set filterEdges(Set edges, Set subGraphVertices) { - return edges.stream().filter(e -> - subGraphVertices.contains(e.getSource()) || subGraphVertices.contains(e.getTarget())) - .filter(e -> !e.getType().equals(EdgeType.EDGE_RULE.getTypeName())) - .collect(Collectors.toSet()); - } - - private Set computeNodeNames(Set edges) { - return edges.stream().flatMap(e -> e.getNodeNames().stream()).collect( - Collectors.toSet()); - } - - private Set computeAllEdges(String initial, boolean parentChild, boolean edgeRules) { - Set result = new HashSet<>(); - List toQuery = new LinkedList<>(); - toQuery.add(initial); - final List toVisit = new LinkedList<>(); - Set visited = new HashSet<>(); - - while (!toQuery.isEmpty()) { - for (String v : toQuery) { - visited.add(v); - - graph.edgesOf(v).forEach(edge -> { - String neighbour = edge.getTarget(); - toVisit.add(neighbour); - - if (EdgeType.CHILD.isType(edge.getType()) && parentChild) { - result.add(new Edge(neighbour, edge.getSource(), EdgeType.PARENT.getTypeName(), - createTooltip(neighbour, edge.getSource(), EdgeType.PARENT.getTypeName(), edge.getLabel()))); - } - - if (EdgeType.EDGE_RULE.isType(edge.getType()) && edgeRules) { - result.add(new Edge(edge.getSource(), neighbour, edge.getLabel(), - createTooltip(neighbour, edge.getSource(), EdgeType.EDGE_RULE.getTypeName(), - edge.getLabel()))); - } - }); - } - toQuery.clear(); - toQuery.addAll( - toVisit.stream().filter(s -> !visited.contains(s)).collect(Collectors.toList())); + private Set computeNodeNames(Set edges) { + return edges.stream() + .flatMap(e -> e.getNodeNames().stream()) + .collect(Collectors.toSet()); } - return result; + private Set computeAllEdges(String initial, boolean parentChild, boolean edgeRules) { + Set result = new HashSet<>(); + List toQuery = new LinkedList<>(); + toQuery.add(initial); + final List toVisit = new LinkedList<>(); + Set visited = new HashSet<>(); + + while (!toQuery.isEmpty()) { + for (String v : toQuery) { + visited.add(v); + + graph.edgesOf(v).forEach(edge -> { + String neighbour = edge.getTarget(); + toVisit.add(neighbour); + + if (EdgeType.CHILD.isType(edge.getType()) && parentChild) { + result.add(new Edge( + neighbour, edge.getSource(), EdgeType.PARENT.getTypeName(), createTooltip( + neighbour, edge.getSource(), EdgeType.PARENT.getTypeName(), edge.getLabel()))); + } + + if (EdgeType.EDGE_RULE.isType(edge.getType()) && edgeRules) { + result.add(new Edge( + edge.getSource(), neighbour, edge.getLabel(), createTooltip( + neighbour, edge.getSource(), EdgeType.EDGE_RULE.getTypeName(), edge.getLabel()))); + } + }); + } + toQuery.clear(); + toQuery.addAll(toVisit.stream().filter(s -> !visited.contains(s)).collect(Collectors.toList())); + } + + return result; + + } - } + private Set computeNodes(String vertex, int hops, String relationshipName) { + List toQuery = new LinkedList<>(); + toQuery.add(vertex); - private Set computeNodes(String vertex, int hops, String relationshipName) { - List toQuery = new LinkedList<>(); - toQuery.add(vertex); + Set visited = new HashSet<>(); + int i = 0; - Set visited = new HashSet<>(); - int i = 0; + final List toVisit = new LinkedList<>(); + while (!toQuery.isEmpty() && hops > i) { + i++; + toVisit.clear(); - final List toVisit = new LinkedList<>(); - while (!toQuery.isEmpty() && hops > i) { - i++; - toVisit.clear(); + for (String v : toQuery) { + visited.add(v); + graph.edgesOf(v).stream() + .filter(e -> e.getType().equals(relationshipName)) + .map(MetadataEdge::getTarget) + .forEach(toVisit::add); + } - for (String v : toQuery) { - visited.add(v); - graph.edgesOf(v).stream().filter(e -> e.getType().equals(relationshipName)).map( - MetadataEdge::getTarget).forEach(toVisit::add); - } + toQuery.clear(); + toQuery.addAll(toVisit.stream().filter(v -> !visited.contains(v)).collect(Collectors.toList())); + } - toQuery.clear(); - toQuery - .addAll(toVisit.stream().filter(v -> !visited.contains(v)).collect(Collectors.toList())); + return visited; } - return visited; - } - - - @Override - public org.onap.aai.graphgraph.dto.Graph getGraph(String fromNode, String toNode, - String edgeFilter) { - init(); - Graph tempGraph = createGraph(isParentChildFilter(edgeFilter), isEdgeRulesFilter(edgeFilter)); - List> paths = new LinkedList<>(); - FloydWarshallShortestPaths shortestPaths; - - while (true) { - shortestPaths = new FloydWarshallShortestPaths<>(tempGraph); - GraphPath p = shortestPaths.getPath(fromNode, toNode); - if (p == null || p.getEdgeList() == null || p.getEdgeList().isEmpty()) { - break; - } - String previous = fromNode; - List path = new LinkedList<>(); - for (MetadataEdge e : p.getEdgeList()) { - if (e.getTarget().equals(previous)) { - previous = e.getSource(); - path.add(new NodeName(e.getTarget())); - } else { - previous = e.getTarget(); - path.add(new NodeName(e.getSource())); + @Override + public org.onap.aai.graphgraph.dto.Graph getGraph(String fromNode, String toNode, String edgeFilter) { + init(); + Graph tempGraph = createGraph( + isParentChildFilter(edgeFilter), isEdgeRulesFilter(edgeFilter)); + List> paths = new LinkedList<>(); + FloydWarshallShortestPaths shortestPaths; + + while (true) { + shortestPaths = new FloydWarshallShortestPaths<>(tempGraph); + GraphPath p = shortestPaths.getPath(fromNode, toNode); + if (p == null || p.getEdgeList() == null || p.getEdgeList().isEmpty()) { + break; + } + String previous = fromNode; + List path = new LinkedList<>(); + for (MetadataEdge e : p.getEdgeList()) { + if (e.getTarget().equals(previous)) { + previous = e.getSource(); + path.add(new NodeName(e.getTarget())); + } else { + previous = e.getTarget(); + path.add(new NodeName(e.getSource())); + } + } + path.add(new NodeName(previous)); + paths.add(path); + tempGraph.removeEdge(p.getEdgeList().get(p.getLength() - 1)); //remove last edge from path } - } - path.add(new NodeName(previous)); - paths.add(path); - tempGraph.removeEdge(p.getEdgeList().get(p.getLength() - 1)); //remove last edge from path + + Set edges = computeAllEdges(fromNode, isParentChildFilter(edgeFilter), isEdgeRulesFilter(edgeFilter)); + edges = filterEdgesStrict( + edges, + paths.stream() + .flatMap(Collection::stream) + .map(NodeName::getId) + .collect(Collectors.toSet())); + return new org.onap.aai.graphgraph.dto.Graph( + new LinkedList<>(computeNodeNames(edges)), new LinkedList<>(edges), + paths, getVertexProperties(fromNode)); } - Set edges = computeAllEdges(fromNode, isParentChildFilter(edgeFilter), - isEdgeRulesFilter(edgeFilter)); - edges = filterEdgesStrict(edges, - paths.stream().flatMap(Collection::stream).map(NodeName::getId).collect( - Collectors.toSet())); - return new org.onap.aai.graphgraph.dto.Graph(new LinkedList<>(computeNodeNames(edges)), - new LinkedList<>(edges), paths, getVertexProperties(fromNode)); - } - - private List createTooltip(String target, String v, String type, String label) { - List properties = new LinkedList<>(); - properties.add(new Property("From", target)); - properties.add(new Property("To", v)); - properties.add(new Property("Type", type)); - properties.add(new Property("Relationship", label)); - properties.addAll(getEdgeProperties(v, target, EdgeType.EDGE_RULE.isType(type) ? EdgeType.EDGE_RULE.getTypeName() : EdgeType.PARENT.getTypeName())); - return properties; - } + private List createTooltip(String target, String v, String type, String label) { + List properties = new LinkedList<>(); + properties.add(new Property("From", target)); + properties.add(new Property("To", v)); + properties.add(new Property("Type", type)); + properties.add(new Property("Relationship", label)); + properties.addAll(getEdgeProperties( + v, target, + EdgeType.EDGE_RULE.isType(type) ? EdgeType.EDGE_RULE.getTypeName() : EdgeType.PARENT.getTypeName())); + return properties; + } } diff --git a/src/main/java/org/onap/aai/graphgraph/reader/EdgeType.java b/src/main/java/org/onap/aai/graphgraph/reader/EdgeType.java index 1250474..fd2614c 100644 --- a/src/main/java/org/onap/aai/graphgraph/reader/EdgeType.java +++ b/src/main/java/org/onap/aai/graphgraph/reader/EdgeType.java @@ -1,38 +1,40 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.reader; public enum EdgeType { - EDGE_RULE("edgerule"), PARENT("parent"), CHILD("child"); + EDGE_RULE("edgerule"), + PARENT("parent"), + CHILD("child"); - private final String name; + private final String name; - EdgeType(String s) { - name = s; - } + EdgeType(String s) { + name = s; + } - public String getTypeName() { - return this.name; - } + public String getTypeName() { + return this.name; + } - public boolean isType(String o){ - return name.equals(o); - } + public boolean isType(String o) { + return name.equals(o); + } } diff --git a/src/main/java/org/onap/aai/graphgraph/reader/MetadataEdge.java b/src/main/java/org/onap/aai/graphgraph/reader/MetadataEdge.java index fb8e53f..2dea403 100644 --- a/src/main/java/org/onap/aai/graphgraph/reader/MetadataEdge.java +++ b/src/main/java/org/onap/aai/graphgraph/reader/MetadataEdge.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.reader; @@ -23,49 +23,49 @@ import org.jgrapht.graph.DefaultEdge; public class MetadataEdge extends DefaultEdge { - private final String type; - private final String target; - private final String source; - private final String label; + private final String type; + private final String target; + private final String source; + private final String label; - MetadataEdge(String type, String source, String target) { - this.source = source; - this.target = target; - this.type = type; - this.label = ""; - } + MetadataEdge(String type, String source, String target) { + this.source = source; + this.target = target; + this.type = type; + this.label = ""; + } - MetadataEdge(String type, String target, String source, String label) { - this.type = type; - this.target = target; - this.source = source; - this.label = label; - } + MetadataEdge(String type, String target, String source, String label) { + this.type = type; + this.target = target; + this.source = source; + this.label = label; + } - public String getLabel() { - return label; - } + public String getLabel() { + return label; + } - @Override - public String getTarget() { - return target; - } + @Override + public String getTarget() { + return target; + } - @Override - public String getSource() { - return source; - } + @Override + public String getSource() { + return source; + } - public String getType() { - return type; - } + public String getType() { + return type; + } - @Override - public String toString() { - return "MetadataEdge{" + - "type='" + type + '\'' + - ", target='" + target + '\'' + - ", source='" + source + '\'' + - '}'; - } + @Override + public String toString() { + return "MetadataEdge{" + + "type='" + type + '\'' + + ", target='" + target + '\'' + + ", source='" + source + '\'' + + '}'; + } } diff --git a/src/main/java/org/onap/aai/graphgraph/reader/SchemaReader.java b/src/main/java/org/onap/aai/graphgraph/reader/SchemaReader.java index a924e63..38e1bf6 100644 --- a/src/main/java/org/onap/aai/graphgraph/reader/SchemaReader.java +++ b/src/main/java/org/onap/aai/graphgraph/reader/SchemaReader.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.reader; @@ -27,11 +27,16 @@ import org.onap.aai.graphgraph.dto.Property; import java.util.List; public interface SchemaReader { + String getSchemaName(); + List getAllVertexNames(String edgeFilter); + List getVertexProperties(String nodeName); + List getEdgeProperties(String fromNode, String toNode, String type); - Graph getGraph(String initialNode, int parentHops, int cousinHops, int childHops, - String edgeFilter); + + Graph getGraph(String initialNode, int parentHops, int cousinHops, int childHops, String edgeFilter); + Graph getGraph(String fromNode, String toNode, String edgeFilter); } diff --git a/src/main/java/org/onap/aai/graphgraph/reader/SchemaRepository.java b/src/main/java/org/onap/aai/graphgraph/reader/SchemaRepository.java index f49a669..5764c50 100644 --- a/src/main/java/org/onap/aai/graphgraph/reader/SchemaRepository.java +++ b/src/main/java/org/onap/aai/graphgraph/reader/SchemaRepository.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.reader; @@ -24,20 +24,22 @@ import java.util.Optional; import java.util.stream.Collectors; public class SchemaRepository { + private List readers; public SchemaRepository(List readers) { this.readers = readers; } - public List getAllSchemaNames(){ + public List getAllSchemaNames() { return readers.stream().map(SchemaReader::getSchemaName).collect(Collectors.toList()); } - public SchemaReader getSchemaReader(String schemaName){ + public SchemaReader getSchemaReader(String schemaName) { Optional reader = readers.stream().filter(r -> schemaName.equals(r.getSchemaName())).findFirst(); - if(!reader.isPresent()) + if (!reader.isPresent()) { throw new IllegalArgumentException("Schema " + schemaName + " not found"); + } return reader.get(); } diff --git a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityAssociation.java b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityAssociation.java index 697fad1..dda37b5 100644 --- a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityAssociation.java +++ b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityAssociation.java @@ -1,115 +1,113 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.velocity; public class VelocityAssociation extends VelocityId { - private final String name; - private final VelocityEntity fromEntity; - private final VelocityEntity toEntity; - private final String fromId = getRandomId(); - private final String toId = getRandomId(); - private final String multiplicity; - private final boolean isComposition; - - public VelocityAssociation(VelocityEntity fromEntity, - VelocityEntity toEntity, String name, String multiplicity, boolean isComposition) { - this.fromEntity = fromEntity; - this.toEntity = toEntity; - this.name = name; - this.multiplicity = multiplicity; - this.isComposition = isComposition; - } - - public String getFromEntityName(){ - return fromEntity.getName(); - } - - public String getToEntityName(){ - return toEntity.getName(); - } - - public String getFromEntityId(){ - return fromEntity.getId(); - } - - public String getToEntityId(){ - return toEntity.getId(); - } - - public String getFromId() { - return fromId; - } - - public String getToId() { - return toId; - } - - public String getName() { - return name; - } - - public String getMultiplicity() { - return multiplicity.toUpperCase(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + private final String name; + private final VelocityEntity fromEntity; + private final VelocityEntity toEntity; + private final String fromId = getRandomId(); + private final String toId = getRandomId(); + private final String multiplicity; + private final boolean isComposition; + + public VelocityAssociation(VelocityEntity fromEntity, + VelocityEntity toEntity, String name, String multiplicity, boolean isComposition) { + this.fromEntity = fromEntity; + this.toEntity = toEntity; + this.name = name; + this.multiplicity = multiplicity; + this.isComposition = isComposition; } - if (o == null || getClass() != o.getClass()) { - return false; + + public String getFromEntityName() { + return fromEntity.getName(); + } + + public String getToEntityName() { + return toEntity.getName(); + } + + public String getFromEntityId() { + return fromEntity.getId(); } - VelocityAssociation that = (VelocityAssociation) o; + public String getToEntityId() { + return toEntity.getId(); + } + + public String getFromId() { + return fromId; + } + + public String getToId() { + return toId; + } - if (!name.equals(that.name)) { - return false; + public String getName() { + return name; } - if (!fromEntity.equals(that.fromEntity)) { - return false; + + public String getMultiplicity() { + return multiplicity.toUpperCase(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + VelocityAssociation that = (VelocityAssociation) o; + + if (!name.equals(that.name)) { + return false; + } + if (!fromEntity.equals(that.fromEntity)) { + return false; + } + return toEntity.equals(that.toEntity); + } + + public boolean getIsComposition() { + return isComposition; + } + + @Override + public String toString() { + return "VelocityAssociation{" + + "name='" + name + '\'' + + ", fromEntity=" + fromEntity + + ", toEntity=" + toEntity + + '}'; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + fromEntity.hashCode(); + result = 31 * result + toEntity.hashCode(); + return result; } - return toEntity.equals(that.toEntity); - } - - public boolean getIsComposition() { - return isComposition; - } - - @Override - public String toString() { - return "VelocityAssociation{" + - "name='" + name + '\'' + - ", fromEntity=" + fromEntity + - ", toEntity=" + toEntity + - '}'; - } - - @Override - public int hashCode() { - int result = name.hashCode(); - result = 31 * result + fromEntity.hashCode(); - result = 31 * result + toEntity.hashCode(); - return result; - - - } } diff --git a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntity.java b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntity.java index 99f94f3..424c0e6 100644 --- a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntity.java +++ b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntity.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.velocity; @@ -24,75 +24,73 @@ import java.util.List; import java.util.Set; public class VelocityEntity extends VelocityId { - private String name; - private String description; - private List neighbours = new LinkedList<>(); - private Set properties; - public Set getProperties() { - return properties; - } + private String name; + private String description; + private List neighbours = new LinkedList<>(); + private Set properties; - public void setProperties(Set properties) { - this.properties = properties; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } + public VelocityEntity(String name) { + this.name = name; + } - public VelocityEntity(String name) { - this.name = name; - } + public Set getProperties() { + return properties; + } - public String getName() { - return name; - } + public void setProperties(Set properties) { + this.properties = properties; + } - public void setName(String name) { - this.name = name; - } + public String getDescription() { + return description; + } - public List getNeighbours() { - return neighbours; - } + public void setDescription(String description) { + this.description = description; + } - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } + public String getName() { + return name; + } - public void addNeighbours(VelocityAssociation neighbour) { - neighbours.add(neighbour); - } + public void setName(String name) { + this.name = name; + } + public List getNeighbours() { + return neighbours; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; } - if (o == null || getClass() != o.getClass()) { - return false; + + public void addNeighbours(VelocityAssociation neighbour) { + neighbours.add(neighbour); } - VelocityEntity that = (VelocityEntity) o; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } - return name.equals(that.name); - } + VelocityEntity that = (VelocityEntity) o; - @Override - public int hashCode() { - return name.hashCode(); - } + return name.equals(that.name); + } - @Override - public String toString() { - return "VelocityEntity{" + - "name='" + name + '\'' + - '}'; - } + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return "VelocityEntity{" + "name='" + name + '\'' + '}'; + } } diff --git a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntityProperty.java b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntityProperty.java index e8dec9f..2c65ae3 100644 --- a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntityProperty.java +++ b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityEntityProperty.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.velocity; @@ -24,35 +24,33 @@ import org.onap.aai.graphgraph.dto.Property; public class VelocityEntityProperty extends Property { - private final VelocityEntity entity; - private final String propertyId; - public VelocityEntityProperty(String propertyName, String propertyValue, VelocityEntity entity) { - super(propertyName, propertyValue); - this.entity = entity; - propertyId = entity != null ? entity.getRandomId() : UUID.randomUUID().toString(); - } - - public String getEntityId() { - return entity.getId(); - } - - public String getEntityName() { - return entity.getName(); - } - - public boolean hasEntity(){ - return entity != null; - } - - public String getPropertyId() { - return propertyId; - } - - @Override - public String toString() { - return "VelocityEntityProperty{" + - " name=" + getPropertyName() + - " type=" + getPropertyValue() + - '}'; - } + private final VelocityEntity entity; + private final String propertyId; + + public VelocityEntityProperty(String propertyName, String propertyValue, VelocityEntity entity) { + super(propertyName, propertyValue); + this.entity = entity; + propertyId = entity != null ? entity.getRandomId() : UUID.randomUUID().toString(); + } + + public String getEntityId() { + return entity.getId(); + } + + public String getEntityName() { + return entity.getName(); + } + + public boolean hasEntity() { + return entity != null; + } + + public String getPropertyId() { + return propertyId; + } + + @Override + public String toString() { + return "VelocityEntityProperty{" + " name=" + getPropertyName() + " type=" + getPropertyValue() + '}'; + } } diff --git a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityId.java b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityId.java index fc44a5e..9b59c82 100644 --- a/src/main/java/org/onap/aai/graphgraph/velocity/VelocityId.java +++ b/src/main/java/org/onap/aai/graphgraph/velocity/VelocityId.java @@ -1,34 +1,35 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2019 Orange Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph.velocity; import java.util.UUID; public abstract class VelocityId { - private String id = getRandomId(); - public String getId() { - return id; - } + private String id = getRandomId(); + + public String getId() { + return id; + } - public String getRandomId() { - return UUID.randomUUID().toString(); - } + public String getRandomId() { + return UUID.randomUUID().toString(); + } } diff --git a/src/main/resources/docker-assembly.xml b/src/main/resources/docker-assembly.xml index afd1970..54a87af 100644 --- a/src/main/resources/docker-assembly.xml +++ b/src/main/resources/docker-assembly.xml @@ -1,6 +1,6 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd"> distribution jar @@ -13,11 +13,11 @@ - - + + target/${project.artifactId}-${project.version}.${project.packaging} / false - - \ No newline at end of file + + diff --git a/src/main/resources/etc/auth/realm.properties b/src/main/resources/etc/auth/realm.properties index f0e0172..3ba96bc 100644 --- a/src/main/resources/etc/auth/realm.properties +++ b/src/main/resources/etc/auth/realm.properties @@ -1,13 +1,13 @@ # format : username: password[,rolename ...] # default username/password: AAI/AAI, MSO/MSO, ModelLoader/ModelLoader... -AAI:OBF:1gfr1ev31gg7,admin -MSO:OBF:1jzx1lz31k01,admin -SDNC:OBF:1itr1i0l1i151isv,admin -DCAE:OBF:1g8u1f9d1f991g8w,admin -POLICY:OBF:1mk61i171ima1im41i0j1mko,admin -ASDC:OBF:1f991j0u1j001f9d,admin -VID:OBF:1jm91i0v1jl9,admin -APPC:OBF:1f991ksf1ksf1f9d,admin -ModelLoader:OBF:1qvu1v2h1sov1sar1wfw1j7j1wg21saj1sov1v1x1qxw,admin -AaiUI:OBF:1gfr1p571unz1p4j1gg7,admin -OOF:OBF:1img1ke71ily,admin +AAI=OBF:1gfr1ev31gg7,admin +MSO=OBF:1jzx1lz31k01,admin +SDNC=OBF:1itr1i0l1i151isv,admin +DCAE=OBF:1g8u1f9d1f991g8w,admin +POLICY=OBF:1mk61i171ima1im41i0j1mko,admin +ASDC=OBF:1f991j0u1j001f9d,admin +VID=OBF:1jm91i0v1jl9,admin +APPC=OBF:1f991ksf1ksf1f9d,admin +ModelLoader=OBF:1qvu1v2h1sov1sar1wfw1j7j1wg21saj1sov1v1x1qxw,admin +AaiUI=OBF:1gfr1p571unz1p4j1gg7,admin +OOF=OBF:1img1ke71ily,admin diff --git a/src/main/resources/model_export.vm b/src/main/resources/model_export.vm index c461d59..ae92fab 100644 --- a/src/main/resources/model_export.vm +++ b/src/main/resources/model_export.vm @@ -5,148 +5,148 @@ - + #foreach($association in $associationList) - - -
- - - #if($association.multiplicity == "ONE2MANY" || $association.multiplicity == - "MANY2MANY") - - - #else - - - #end - - #if( ! $association.isComposition) - - #if($association.multiplicity == "MANY2ONE" || $association.multiplicity == - "MANY2MANY") - - - #else - - - #end - - #end - + + +
+ + + #if($association.multiplicity == "ONE2MANY" || $association.multiplicity == + "MANY2MANY") + + + #else + + + #end + + #if( ! $association.isComposition) + + #if($association.multiplicity == "MANY2ONE" || $association.multiplicity == + "MANY2MANY") + + + #else + + + #end + + #end + #end - - + + #foreach($entity in $entityList) - - - $entity.description - - #foreach($association in $entity.neighbours) - #if( $association.isComposition) - - #if($association.multiplicity == "MANY2ONE" || $association.multiplicity == - "MANY2MANY") - - - #else - - - #end - - #end - #end - #foreach($prop in $entity.properties) - #if($prop.propertyValue.contains("java.lang")) - - #if($prop.propertyValue == "java.lang.String") - - #end# - #if($prop.propertyValue == "java.lang.Long") - - #end - #if($prop.propertyValue == "java.lang.Boolean") - - #end - #if($prop.propertyValue == "java.lang.Integer") - - #end - - #elseif(! $prop.hasEntity) - #* *# - #else - - #end - #end - - #end - - - -
-
-
-
-
- - - - - - - - -
-
-
-
-
- - - - - - - - -#foreach($association in $associationList) - -#if( ! $association.isComposition) - -#end -#end -#foreach($entity in $entityList) - - #foreach($association in $entity.neighbours) + + + $entity.description + + #foreach($association in $entity.neighbours) #if( $association.isComposition) - + + #if($association.multiplicity == "MANY2ONE" || $association.multiplicity == + "MANY2MANY") + + + #else + + + #end + #end - #end - #foreach($prop in $entity.properties) - - #end -#end - \ No newline at end of file + #end + #foreach($prop in $entity.properties) + #if($prop.propertyValue.contains("java.lang")) + + #if($prop.propertyValue == "java.lang.String") + + #end# + #if($prop.propertyValue == "java.lang.Long") + + #end + #if($prop.propertyValue == "java.lang.Boolean") + + #end + #if($prop.propertyValue == "java.lang.Integer") + + #end + + #elseif(! $prop.hasEntity) + #* *# + #else + + #end + #end + + #end + + + +
+
+
+
+
+ + + + + + + + +
+
+
+
+
+ + + + + + + + + #foreach($association in $associationList) + + #if( ! $association.isComposition) + + #end + #end + #foreach($entity in $entityList) + + #foreach($association in $entity.neighbours) + #if( $association.isComposition) + + #end + #end + #foreach($prop in $entity.properties) + + #end + #end + diff --git a/src/test/java/org/onap/aai/graphgraph/AppTest.java b/src/test/java/org/onap/aai/graphgraph/AppTest.java index 7879fc3..5393d26 100644 --- a/src/test/java/org/onap/aai/graphgraph/AppTest.java +++ b/src/test/java/org/onap/aai/graphgraph/AppTest.java @@ -1,21 +1,21 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= +/* + ============LICENSE_START======================================================= + org.onap.aai + ================================================================================ + Copyright © 2019-2020 Orange Intellectual Property. All rights reserved. + ================================================================================ + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + ============LICENSE_END========================================================= */ package org.onap.aai.graphgraph; @@ -26,7 +26,7 @@ import org.junit.Test; /** * Unit test for simple App. */ -public class AppTest +public class AppTest { /** * Rigorous Test :-) -- cgit 1.2.3-korg