diff options
Diffstat (limited to 'catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j')
16 files changed, 2508 insertions, 0 deletions
diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/BatchBuilder.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/BatchBuilder.java new file mode 100644 index 0000000000..0177d0bd70 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/BatchBuilder.java @@ -0,0 +1,83 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.openecomp.sdc.be.dao.graph.datatype.GraphElement; +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; +import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation; + +public class BatchBuilder { + // private Map<String, List<Neo4jNode>> nodes; + // private List<Neo4jRelation> relations; + // + private List<GraphElement> elements; + + // TODO add filter + + protected BatchBuilder() { + // nodes = new HashMap<String, List<Neo4jNode>>(); + // relations = new ArrayList<Neo4jRelation>(); + elements = new ArrayList<GraphElement>(); + } + + public static BatchBuilder getBuilder() { + return new BatchBuilder(); + } + + public BatchBuilder add(GraphElement element) { + elements.add(element); + return this; + } + + public List<GraphElement> getElements() { + return elements; + } + + // public BatchBuilder add( Neo4jNode element ){ + // String label = element.getLabel(); + // List<Neo4jNode> list = nodes.get(label); + // if ( list == null ){ + // list = new ArrayList<Neo4jNode>(); + // } + // list.add(element); + // nodes.put(label, list); + + // return this; + // } + // public BatchBuilder add( Neo4jRelation relation ){ + // relations.add(relation); + // return this; + // } + // + // public Map<String, List<Neo4jNode>> getNodes() { + // return nodes; + // } + // + // public List<Neo4jRelation> getRelations() { + // return relations; + // } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTemplates.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTemplates.java new file mode 100644 index 0000000000..b0b2cc20bb --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTemplates.java @@ -0,0 +1,52 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +public interface CypherTemplates { + + public static final String CypherUrlTemplate = "http://$host$:$port$/db/data/transaction/commit"; + public static final String batchTemplate = "http://$host$:$port$/db/data/batch"; + public static final String getAllIndexsTemplate = "http://$host$:$port$/db/data/schema/index"; + + public static final String CypherCreateNodeTemplate = "{\n\"statements\" : [ {\n \"statement\" : \"CREATE (n:$label$ { props } ) RETURN n\",\n \"parameters\" : { \n \"props\" : $props$ \n } } ] }"; + + public static final String CypherMatchTemplate = "{\"statements\": [{\"statement\": \"MATCH (n:$label$ {$filter$}) RETURN ($type$) \" }]}"; + + public static final String CypherUpdateTemplate = "{\"statements\": [{\"statement\": \"MATCH (n:$label$ {$filter$}) SET n += {props} RETURN ($type$) \",\"parameters\" : {\"props\" : {$props$}}}]}"; + public static final String CypherDeleteNodeTemplate = "{\"statements\": [{\"statement\": \"MATCH ( n:$label$ {$filter$} ) DELETE n \" }]}"; + + public static final String BatchTemplate = "{ \"statements\" : [ $statementList$ ] }"; + + public static final String RegularStatementTemplate = "{ \"statement\" : $statement$ }"; + + public static final String CreateSingleNodeTemplate = " \"CREATE (n:$label$ { props } ) RETURN n, labels(n)\", \"parameters\" : { \"props\" : $props$ }"; + + public static final String CreateRelationTemplate = "\"MATCH (a:$labelFrom$),(b:$labelTo$) WHERE a.$idNameFrom$ = '$idValueFrom$' AND b.$idNameTo$ = '$idvalueTo$' CREATE (a)-[r:$type$ { props } ]->(b) RETURN a, labels(a), b, labels(b), r, type(r)\", \"parameters\": {\"props\": $props$ } "; + + public static final String CreateRelationTemplateNoProps = "\"MATCH (a:$labelFrom$),(b:$labelTo$) WHERE a.$idNameFrom$ = '$idValueFrom$' AND b.$idNameTo$ = '$idvalueTo$' CREATE (a)-[r:$type$ ]->(b) RETURN a,labels(a), b, labels(b), r, type(r)\""; + + public static final String UpdateNodeStatementTemplate = "\"MATCH (n:$label$ {$filter$}) SET n += {props} \",\"parameters\" : {\"props\" : $props$}"; + + public static final String GetNodeRecursiveTemplate = "\"MATCH (m:$label$ {$filter$} )-[f$typesList$]->l RETURN m, labels(m), l, labels(l),f, type(f)\""; + + public static final String GetByRelationNodeRecursiveTemplate = "\"MATCH (n:$labelNode$ ($propsNode$} )-[r:$type$ {$propsRel$}]->(m:$labelSrc$)-[f$typesList$]->l RETURN n, labels(n), r, type(r), m, labels(m), l, labels(l),f, type(f)\""; + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTranslator.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTranslator.java new file mode 100644 index 0000000000..e1409b3bb1 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/CypherTranslator.java @@ -0,0 +1,251 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.openecomp.sdc.be.dao.graph.datatype.GraphElement; +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; +import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation; +import org.openecomp.sdc.be.dao.graph.datatype.RelationEndPoint; +import org.openecomp.sdc.be.dao.neo4j.filters.MatchFilter; +import org.openecomp.sdc.be.dao.neo4j.filters.RecursiveByRelationFilter; +import org.openecomp.sdc.be.dao.neo4j.filters.RecursiveFilter; +import org.openecomp.sdc.be.dao.utils.DaoUtils; + +public class CypherTranslator { + + public String translate(BatchBuilder builder) { + String json = null; + StringBuilder statementList = new StringBuilder(); + + List<GraphElement> elements = builder.getElements(); + int statementCounter = 0; + for (GraphElement element : elements) { + String singleStatementBody = null; + switch (element.getElementType()) { + case Node: + singleStatementBody = prepareNodeStatement(element); + break; + case Relationship: + singleStatementBody = prepareRelationStatement(element); + break; + } + if (singleStatementBody != null && !singleStatementBody.isEmpty()) { + + String singleStatement = CypherTemplates.RegularStatementTemplate.replace("$statement$", + singleStatementBody); + + statementList.append(singleStatement); + } + ++statementCounter; + if (statementCounter < elements.size() && singleStatementBody != null) { + statementList.append(","); + } + + } + json = CypherTemplates.BatchTemplate.replace("$statementList$", statementList.toString()); + return json; + } + + private String prepareNodeStatement(GraphElement element) { + if (element instanceof GraphNode) { + GraphNode node = (GraphNode) element; + + switch (node.getAction()) { + case Create: + return createNodeStatement(node); + case Update: + return updateNodeStatement(node); + case Delete: + // TODO + break; + default: + break; + } + } + return null; + } + + private String updateNodeStatement(GraphNode node) { + String singleStatement = CypherTemplates.UpdateNodeStatementTemplate.replace("$label$", node.getLabel()); + String filter = prepareKeyValueFilter(node); + + singleStatement = singleStatement.replace("$filter$", filter); + + singleStatement = singleStatement.replace("$props$", DaoUtils.convertToJson(node.toGraphMap())); + + return singleStatement; + } + + private String createNodeStatement(GraphNode node) { + String singleStatement = CypherTemplates.CreateSingleNodeTemplate.replace("$label$", node.getLabel()); + + singleStatement = singleStatement.replace("$props$", DaoUtils.convertToJson(node.toGraphMap())); + return singleStatement; + } + + private String prepareRelationStatement(GraphElement element) { + if (element instanceof GraphRelation) { + + GraphRelation relation = (GraphRelation) element; + + switch (relation.getAction()) { + case Create: + return createRelationStatement(relation); + case Update: + return updateRelationStatement(relation); + case Delete: + // TODO + break; + default: + break; + } + } + return null; + } + + private String createRelationStatement(GraphRelation relation) { + RelationEndPoint from = relation.getFrom(); + String singleStatement; + + Map<String, Object> props = relation.toGraphMap(); + if (props == null || props.isEmpty()) { + singleStatement = CypherTemplates.CreateRelationTemplateNoProps.replace("$labelFrom$", + from.getLabel().getName()); + } else { + singleStatement = CypherTemplates.CreateRelationTemplate.replace("$labelFrom$", from.getLabel().getName()); + singleStatement = singleStatement.replace("$props$", DaoUtils.convertToJson(props)); + } + + singleStatement = singleStatement.replace("$idNameFrom$", from.getIdName()); + singleStatement = singleStatement.replace("$idValueFrom$", from.getIdValue().toString()); + + RelationEndPoint to = relation.getTo(); + singleStatement = singleStatement.replace("$labelTo$", to.getLabel().getName()); + singleStatement = singleStatement.replace("$idNameTo$", to.getIdName()); + singleStatement = singleStatement.replace("$idvalueTo$", to.getIdValue().toString()); + + singleStatement = singleStatement.replace("$type$", relation.getType()); + return singleStatement; + } + + private String updateRelationStatement(GraphRelation relation) { + // TODO + return null; + } + + private String prepareKeyValueFilter(GraphNode node) { + StringBuilder sb = new StringBuilder(); + + ImmutablePair<String, Object> keyValueId = node.getKeyValueId(); + + sb.append(keyValueId.getKey()).append(":"); + if (keyValueId.getValue() instanceof String) { + sb.append("'"); + } + sb.append(keyValueId.getValue()); + + if (keyValueId.getValue() instanceof String) { + sb.append("'"); + } + + return sb.toString(); + } + + public String translateGet(RecursiveFilter filter) { + String requestJson = null; + String statement; + + if (filter instanceof RecursiveByRelationFilter) { + RecursiveByRelationFilter byRelationFilter = (RecursiveByRelationFilter) filter; + + statement = CypherTemplates.GetByRelationNodeRecursiveTemplate.replace("$labelNode$", + byRelationFilter.getNode().getLabel()); + String keyValueId = prepareKeyValueFilter(byRelationFilter.getNode()); + + statement = statement.replace("$propsNode$", keyValueId); + + statement = statement.replace("$type$", byRelationFilter.getRelationType()); + + String relationProps = prepareFilterBody(filter); + statement = statement.replace("$propsRel$", relationProps); + statement = statement.replace("$labelSrc$", filter.getNodeType().getName()); + + } else { + + statement = CypherTemplates.GetNodeRecursiveTemplate.replace("$label$", filter.getNodeType().getName()); + + // replace filter + if (filter.getProperties().isEmpty()) { + // get all records by label + statement = statement.replace("{$filter$}", ""); + } else { + String filterStr = prepareFilterBody(filter); + statement = statement.replace("$filter$", filterStr); + } + } + + if (filter.getChildRelationTypes() == null || filter.getChildRelationTypes().isEmpty()) { + statement = statement.replace("$typesList$", ""); + + } else { + StringBuilder typesList = new StringBuilder(); + int count = 0; + for (String type : filter.getChildRelationTypes()) { + typesList.append(":").append(type); + ++count; + if (count < filter.getChildRelationTypes().size()) { + typesList.append("|"); + } + } + statement = statement.replace("$typesList$", typesList.toString()); + } + String singleStatement = CypherTemplates.RegularStatementTemplate.replace("$statement$", statement); + requestJson = CypherTemplates.BatchTemplate.replace("$statementList$", singleStatement); + + return requestJson; + } + + public static String prepareFilterBody(MatchFilter filter) { + StringBuilder sb = new StringBuilder(); + int count = 0; + int size = filter.getProperties().entrySet().size(); + for (Map.Entry<String, Object> entry : filter.getProperties().entrySet()) { + sb.append(entry.getKey()).append(":"); + if (entry.getValue() instanceof String) { + sb.append("'"); + } + sb.append(entry.getValue()); + if (entry.getValue() instanceof String) { + sb.append("'"); + } + ++count; + if (count < size) { + sb.append(","); + } + } + return sb.toString(); + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgeLabels.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgeLabels.java new file mode 100644 index 0000000000..917bcbb986 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgeLabels.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.List; + +public enum GraphEdgeLabels { + + // field name + // + STATE("STATE"), LAST_STATE("LAST_STATE"), CREATOR("CREATOR"), LAST_MODIFIER("LAST_MODIFIER"), ATTRIBUTE( + "EDGE_ATTRIBUTE"), PROPERTY("EDGE_PROPERTY"), CATEGORY("CATEGORY"), DERIVED_FROM( + "DERIVED_FROM"), REQUIREMENT("REQUIREMENT"), CAPABILITY_TYPE("CAPABILITY_TYPE"), RELATIONSHIP_TYPE( + "RELATIONSHIP_TYPE"), CAPABILITY("CAPABILITY"), INSTANCE_OF("INSTANCE_OF"), INTERFACE( + "INTERFACE"), INTERFACE_OPERATION("INTERFACE_OPERATION"), ARTIFACT_REF( + "ARTIFACT_REF"), INPUTS("INPUTS"), REQUIREMENT_IMPL( + "REQUIREMENT_IMPL"), NODE_IMPL("NODE_IMPL"), IMPLEMENTATION_OF( + "IMPLEMENTATION_OF"), ATTRIBUTE_VALUE( + "ATTRIBUTE_VALUE"), INPUT_VALUE( + "INPUT_VALUE"), PROPERTY_VALUE( + "PROPERTY_VALUE"), CAPABILITY_INST( + "CAPABILITY_INST"), TYPE_OF( + "TYPE_OF"), RESOURCE_INST( + "RESOURCE_INST"), RELATIONSHIP_INST( + "RELATIONSHIP_INST"), CAPABILITY_NODE( + "CAPABILITY_NODE"), LAST_DISTRIBUTION_STATE_MODIFAIER( + "LAST_DISTRIBUTION_STATE_MODIFAIER"), ATTRIBUTE_IMPL( + "ATTRIBUTE_IMPL"), INPUT_IMPL( + "INPUT_IMPL"), PROPERTY_IMPL( + "PROPERTY_IMPL"), ADDITIONAL_INFORMATION( + "ADDITIONAL_INFORMATION"), HEAT_PARAMETER( + "HEAT_PARAMETER"), SUB_CATEGORY( + "SUB_CATEGORY"), GROUPING( + "GROUPING"), CATEGORIZED_TO( + "CATEGORIZED_TO"), GENERATED_FROM( + "GENERATED_FROM"), PARAMETER_VALUE( + "PARAMETER_VALUE"), PARAMETER_IMPL( + "PARAMETER_IMPL"), + // VF additions + CALCULATED_REQUIREMENT("CALCULATED_REQUIREMENT"), CALCULATED_CAPABILITY( + "CALCULATED_CAPABILITY"), RELATIONSHIP_ORIGIN("RELATIONSHIP_ORIGIN"), CAPABILITY_ORIGIN( + "CAPABILITY_ORIGIN"), CALCULATED_REQUIREMENT_FULLFILLED( + "CALCULATED_REQUIREMENT_FULLFILLED"), CALCULATED_CAPABILITY_FULLFILLED( + "CALCULATED_CAPABILITY_FULLFILLED"), + // Group + GROUP("GROUP"), GROUP_ARTIFACT_REF("GROUP_ARTIFACT_REF"), GROUP_MEMBER("GROUP_MEMBER"), INPUT( + "EDGE_INPUT"), GET_INPUT("GET_INPUT"),; + + private String property; + + GraphEdgeLabels(String property) { + this.property = property; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public static List<String> getAllProperties() { + + List<String> arrayList = new ArrayList<String>(); + + for (GraphEdgeLabels graphProperty : GraphEdgeLabels.values()) { + arrayList.add(graphProperty.getProperty()); + } + + return arrayList; + } + + public static GraphEdgeLabels getByName(String property) { + for (GraphEdgeLabels inst : GraphEdgeLabels.values()) { + if (inst.getProperty().equals(property)) { + return inst; + } + } + return null; + } +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgePropertiesDictionary.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgePropertiesDictionary.java new file mode 100644 index 0000000000..18c9ecb6f7 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphEdgePropertiesDictionary.java @@ -0,0 +1,80 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; + +public enum GraphEdgePropertiesDictionary { + + // field name class type + // stored in graph + STATE("state", String.class), NAME("name", String.class), GROUP_TYPE("groupType", String.class), SOURCE("source", + String.class), OWNER_ID("ownerId", String.class), REQUIRED_OCCURRENCES("requiredOccurrences", + String.class), LEFT_OCCURRENCES("leftOccurrences", + String.class), GET_INPUT_INDEX("get_input_index", String.class); + + private String property; + private Class clazz; + + GraphEdgePropertiesDictionary(String property, Class clazz) { + this.property = property; + this.clazz = clazz; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public Class getClazz() { + return clazz; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public static List<String> getAllProperties() { + + List<String> arrayList = new ArrayList<String>(); + + for (GraphEdgePropertiesDictionary graphProperty : GraphEdgePropertiesDictionary.values()) { + arrayList.add(graphProperty.getProperty()); + } + + return arrayList; + } + + public static GraphEdgePropertiesDictionary getByName(String property) { + for (GraphEdgePropertiesDictionary inst : GraphEdgePropertiesDictionary.values()) { + if (inst.getProperty().equals(property)) { + return inst; + } + } + return null; + } +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphNeighbourTable.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphNeighbourTable.java new file mode 100644 index 0000000000..ccfb57b145 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphNeighbourTable.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; + +public class GraphNeighbourTable { + + List<GraphNode> nodes = new ArrayList<GraphNode>(); + + List<NodeRelation> directedEdges = new ArrayList<NodeRelation>(); + + public List<GraphNode> getNodes() { + return nodes; + } + + public void setNodes(List<GraphNode> nodes) { + this.nodes = nodes; + } + + public List<NodeRelation> getDirectedEdges() { + return directedEdges; + } + + public void setDirectedEdges(List<NodeRelation> directedEdges) { + this.directedEdges = directedEdges; + } + + public int addNode(GraphNode node) { + this.nodes.add(node); + return this.nodes.size() - 1; + } + + public void addEdge(NodeRelation directedEdge) { + this.directedEdges.add(directedEdge); + } + + @Override + public String toString() { + return "GraphNeighbourTable [nodes=" + nodes + ", directedEdges=" + directedEdges + "]"; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java new file mode 100644 index 0000000000..a042ab510e --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/GraphPropertiesDictionary.java @@ -0,0 +1,212 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.List; + + +public enum GraphPropertiesDictionary { +// field name class type unique indexed +// stored in graph index + // Common + LABEL ("nodeLabel", String.class, false, true), + HEALTH_CHECK ("healthcheckis", String.class, true, true), //yavivi + // Resource + NAME ("name", String.class, false, true), + TOSCA_RESOURCE_NAME ("toscaResourceName", String.class, false, true), + CATEGORY_NAME ("categoryName", String.class, false, true), // ? + VERSION ("version", String.class, false, true), + CREATION_DATE ("creationDate", Long.class, false, false), + LAST_UPDATE_DATE ("modificationDate", Long.class, false, false), + IS_HIGHEST_VERSION ("highestVersion", Boolean.class, false, true), + IS_ABSTRACT ("abstract", Boolean.class, false, true), + DESCRIPTION ("description", String.class, false, false), + UNIQUE_ID ("uid", String.class, true, true), + STATE ("state", String.class, false, true), + TYPE ("type", String.class, false, true), + REQUIRED ("required", Boolean.class, false, false), + DEFAULT_VALUE ("defaultValue", String.class, false, false), + CONSTRAINTS ("constraints", String.class, false, false), + CONTACT_ID ("contactId", String.class, false, false), + VENDOR_NAME ("vendorName", String.class, false, false), + VENDOR_RELEASE ("vendorRelease", String.class, false, false), + ICON ("icon", String.class, false, false), + TAGS ("tags", String.class, false, false), + UUID ("uuid", String.class, false, true), + COST ("cost", String.class, false, false), + LICENSE_TYPE ("licenseType", String.class, false, false), + NORMALIZED_NAME ("normalizedName", String.class, false, true), + SYSTEM_NAME ("systemName", String.class, false, true), + IS_DELETED ("deleted", Boolean.class, false, true), + RESOURCE_TYPE ("resourceType", String.class, false, true), + ENTRY_SCHEMA ("entry_schema", String.class, false, false), + CSAR_UUID ("csarUuid", String.class, false, true), + CSAR_VERSION ("csarVersion", String.class, false, true), + IMPORTED_TOSCA_CHECKSUM ("importedToscaChecksum", String.class, false, true), + GENERATED ("generated", Boolean.class, false, false), + // User + USER_ID ("userId", String.class, true, true), + EMAIL ("email", String.class, false, false), + FIRST_NAME ("firstName", String.class, false, false), + LAST_NAME ("lastName", String.class, false, false), + ROLE ("role", String.class, false, true), + USER_STATUS ("status", String.class, false, true), + VALID_SOURCE_TYPES ("validSourceTypes", String.class, false, false), + NODE ("node", String.class, false, false), + VALUE ("value", String.class, false, false), + HIDDEN ("Hidden", Boolean.class, false, false), + PROPERTIES ("properties", String.class, false, false), + POSITION_X ("positionX", String.class, false, false), + POSITION_Y ("positionY", String.class, false, false), + RELATIONSHIP_TYPE ("relationshipType", String.class, false, false), + ARTIFACT_TYPE ("artifactType", String.class, false, true), + ARTIFACT_REF ("artifactRef", String.class, false, false), + ARTIFACT_REPOSITORY ("artifactRepository", String.class, false, false), + ARTIFACT_CHECKSUM ("artifactChecksum", String.class, false, false), + CREATOR ("creator", String.class, false, false), + ATT_CREATOR ("attCreator", String.class, false, false), + LAST_UPDATER ("lastUpdater", String.class, false, false), + CREATOR_FULL_NAME ("creatorFullName", String.class, false, false), + UPDATER_FULL_NAME ("updaterFullName", String.class, false, false), + ES_ID ("esId", String.class, false, false), + ARTIFACT_LABEL ("artifactLabel", String.class, false, true), + ARTIFACT_DISPLAY_NAME("artifactDisplayName", String.class, false, true), + INSTANCE_COUNTER ("instanceCounter", Integer.class, false, false), + PROJECT_CODE ("projectCode", String.class, false, false), + DISTRIBUTION_STATUS ("distributionStatus", String.class, false, false), + IS_VNF ("isVNF", Boolean.class, false, false), + LAST_LOGIN_TIME ("lastLoginTime", Long.class, false, true), + ATTRIBUTE_COUNTER ("attributeCounter", Integer.class, false, false), + INPUT_COUNTER ("inputCounter", Integer.class, false, false), + PROPERTY_COUNTER ("propertyCounter", Integer.class, false, false), + API_URL ("apiUrl", String.class, false, false), + SERVICE_API ("serviceApi", Boolean.class, false, true), + ADDITIONAL_INFO_PARAMS ("additionalInfo", String.class, false, false), + ADDITIONAL_INFO_ID_TO_KEY ("idToKey", String.class, false, false), + ARTIFACT_GROUP_TYPE ("artifactGroupType", String.class, false, true), + ARTIFACT_TIMEOUT ("timeout", Integer.class, false, false), + IS_ACTIVE ("isActive", Boolean.class, false, true), + PROPERTY_VALUE_RULES ("propertyValueRules", String.class, false, false), + //authantication + CONSUMER_NAME ("consumerName", String.class, true, true), + CONSUMER_PASSWORD ("consumerPassword", String.class, false, false), + CONSUMER_SALT ("consumerSalt", String.class, false, false), + CONSUMER_LAST_AUTHENTICATION_TIME ("consumerLastAuthenticationTime", Long.class, false, false), + CONSUMER_DETAILS_LAST_UPDATED_TIME ("consumerDetailsLastupdatedtime", Long.class, false, false), + LAST_MODIFIER_USER_ID("lastModfierUserId", String.class, false, false), + ARTIFACT_VERSION ("artifactVersion", String.class, false, false), + ARTIFACT_UUID ("artifactUUID", String.class, false, false), + PAYLOAD_UPDATE_DATE ("payloadUpdateDate", Long.class, false, false), + HEAT_PARAMS_UPDATE_DATE ("heatParamsUpdateDate",Long.class, false, false), + //product + FULL_NAME ("fullName", String.class, false, true), + //was changed as part of migration from 1602 to 1602 ( in 1602 was defined as unique. it's problem to reconfigure the index ) + CONSTANT_UUID ("constantUuidNew", String.class, false, true), + CONTACTS ("contacts", String.class, false, false), + //categorys + ICONS ("icons", String.class, false, false), + //relation + CAPABILITY_OWNER_ID ("capOwnerId", String.class, false, false), + REQUIREMENT_OWNER_ID ("reqOwnerId", String.class, false, false), + CAPABILITY_ID ("capabiltyId", String.class, false, false), + REQUIREMENT_ID ("requirementId", String.class, false, false), + PROPERTY_ID ("propertyId", String.class, false, false), + PROPERTY_NAME ("propertyName", String.class, false, false), + //component instance + ORIGIN_TYPE ("originType", String.class, false, false), + //requirement & capabilty + MIN_OCCURRENCES ("minOccurrences", String.class, false, false), + MAX_OCCURRENCES ("maxOccurrences", String.class, false, false), + //Data type + DERIVED_FROM ("derivedFrom", String.class, false, false), + MEMBERS ("members", String.class, false, false), + TARGETS ("targets ", String.class, false, false), + METADATA ("metadata", String.class, false, false), + INVARIANT_UUID ("invariantUuid", String.class, false, true), + IS_BASE ("isBase", Boolean.class, false, true), + GROUP_UUID ("groupUuid", String.class, false, true), + STATUS ("status", String.class, false, false), + FUNCTIONAL_MENU ("functionalMenu", String.class, false, false), + REQUIRED_ARTIFACTS ("requiredArtifacts", String.class, false, false), + ; + + + + private String property; + private Class clazz; + private boolean unique; + private boolean indexed; + + + GraphPropertiesDictionary(String property,Class clazz, boolean unique,boolean indexed) { + this.property = property; + this.clazz = clazz; + this.unique = unique; + this.indexed = indexed; + } + + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public Class getClazz() { + return clazz; + } + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public boolean isUnique() { + return unique; + } + public void setUnique(boolean unique) { + this.unique = unique; + } + + public boolean isIndexed() { + return indexed; + } + + + public void setIndexed(boolean indexed) { + this.indexed = indexed; + } + + + public static List<String> getAllProperties() { + + List<String> arrayList = new ArrayList<String>(); + + for (GraphPropertiesDictionary graphProperty : GraphPropertiesDictionary + .values()) { + arrayList.add(graphProperty.getProperty()); + } + + return arrayList; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jClient.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jClient.java new file mode 100644 index 0000000000..8bab8d8a8f --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jClient.java @@ -0,0 +1,1004 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpResponseException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.BasicResponseHandler; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.graph.GraphElementFactory; +import org.openecomp.sdc.be.dao.graph.datatype.GraphElement; +import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum; +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; +import org.openecomp.sdc.be.dao.neo4j.filters.MatchFilter; +import org.openecomp.sdc.be.dao.neo4j.filters.RecursiveFilter; +import org.openecomp.sdc.be.dao.neo4j.filters.UpdateFilter; +import org.openecomp.sdc.be.dao.utils.DaoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import fj.data.Either; + +//@Component("neo4j-client") +public class Neo4jClient { + private CloseableHttpClient httpClient; + private JSONParser jsonParser; + + private CypherTranslator cypherTranslator; + + private static Logger logger = LoggerFactory.getLogger(Neo4jClient.class.getName()); + + private static final String getServiceRoot = "http://$host$:$port$/db/data/"; + // Error's Classification templates + private static final String ClientError = "ClientError"; + private static final String DatabaseError = "DatabaseError"; + private static final String TransientError = "TransientError"; + + // Error's Category templates + private static final String General = "General"; + private static final String LegacyIndex = "LegacyIndex"; + private static final String Request = "Request"; + private static final String Schema = "Schema"; + private static final String Security = "Security"; + private static final String Statement = "Statement"; + private static final String Transaction = "Transaction"; + + // Error's Title templates + private static final String EntityNotFound = "EntityNotFound"; + private static final String ConstraintViolation = "ConstraintViolation"; + + @PostConstruct + public void init() { + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(100); + connectionManager.setDefaultMaxPerRoute(20); + connectionManager.setValidateAfterInactivity(15000); + this.httpClient = HttpClients.custom().setConnectionManager(connectionManager).build(); + jsonParser = new JSONParser(); + cypherTranslator = new CypherTranslator(); + + } + + @PreDestroy + public void shutdown() { + try { + httpClient.close(); + logger.debug("Http client to Neo4j Graph closed"); + } catch (Exception e) { + logger.info("Failed to close http client", e); + } + } + + /** + * + * @param builder + * @return + */ + public Either<List<List<GraphElement>>, Neo4jOperationStatus> execute(BatchBuilder builder) { + + String json = cypherTranslator.translate(builder); + logger.debug("Try to execute cypher request [ {} ]", json); + + Either<String, Neo4jOperationStatus> result = sendPostCypher(json); + if (result.isRight()) { + return Either.right(result.right().value()); + } + List<List<GraphElement>> batchResult; + try { + batchResult = parseResult(result.left().value(), false); + } catch (ParseException e) { + logger.error("Failed to parse batchresponse", e); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + + return Either.left(batchResult); + } + + public Either<List<List<GraphElement>>, Neo4jOperationStatus> executeGet(RecursiveFilter filter) { + String json = cypherTranslator.translateGet(filter); + logger.debug("Try to execute cypher request [ {} ]", json); + + Either<String, Neo4jOperationStatus> result = sendPostCypher(json); + if (result.isRight()) { + return Either.right(result.right().value()); + } + List<List<GraphElement>> batchResult; + try { + batchResult = parseResult(result.left().value(), true); + } catch (ParseException e) { + logger.error("Failed to parse batchresponse", e); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + + return Either.left(batchResult); + + } + + /** + * + * @param element + * @param ip + * @param user + * @param password + * @return + */ + public Neo4jOperationStatus createElement(GraphElement element) { + Neo4jOperationStatus result = Neo4jOperationStatus.OK; + switch (element.getElementType()) { + case Node: + Either<String, Neo4jOperationStatus> status = createNode(element); + if (status.isRight()) { + result = status.right().value(); + } + break; + case Relationship: + // TODO + break; + + default: + break; + } + + return result; + } + + public Either<GraphElement, Neo4jOperationStatus> createSingleElement(GraphElement element) { + switch (element.getElementType()) { + case Node: + Either<String, Neo4jOperationStatus> status = createNode(element); + if (status.isRight()) { + return Either.right(status.right().value()); + } + // parse response + String response = status.left().value(); + try { + List<GraphElement> listElements = parseGetResponse(element.getElementType(), + ((GraphNode) element).getLabel(), response); + if (listElements == null || listElements.isEmpty()) { + return Either.right(Neo4jOperationStatus.NOT_FOUND); + } else { + return Either.left(listElements.get(0)); + } + } catch (Exception e) { + logger.error("Failed to parse fetched data from graph", e); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + case Relationship: + // TODO + break; + + default: + break; + } + + return Either.right(Neo4jOperationStatus.NOT_SUPPORTED); + } + + /** + * + * @param type + * @param label + * @param filter + * @param ip + * @param user + * @param password + * @return + */ + public Either<List<GraphElement>, Neo4jOperationStatus> getByFilter(GraphElementTypeEnum type, String label, + MatchFilter filter) { + + List<GraphElement> result = null; + + String requestJson; + // replace return type + if (type.equals(GraphElementTypeEnum.Node)) { + requestJson = CypherTemplates.CypherMatchTemplate.replace("$type$", "n"); + } else { + requestJson = CypherTemplates.CypherMatchTemplate.replace("$type$", "r"); + } + // replace label + if (label != null && !label.isEmpty()) { + requestJson = requestJson.replace("$label$", label); + } else { + requestJson = requestJson.replace("$label$", ""); + } + + // replace filter + if (filter.getProperties().isEmpty()) { + // get all records by label + requestJson = requestJson.replace("{$filter$}", ""); + } else { + String filterStr = CypherTranslator.prepareFilterBody(filter); + requestJson = requestJson.replace("$filter$", filterStr); + } + logger.debug("Try to perform request [ {} ]", requestJson); + + Either<String, Neo4jOperationStatus> status = sendPostCypher(requestJson); + if (status.isRight()) { + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + // parse response + String response = status.left().value(); + try { + result = parseGetResponse(type, label, response); + } catch (Exception e) { + logger.error("Failed to parse fetched data from graph", e); + Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + + return Either.left(result); + } + + /** + * + * @param type + * @param label + * @param toMatch + * @param toUpdate + * @param ip + * @param user + * @param password + * @return + */ + public Neo4jOperationStatus updateElement(GraphElementTypeEnum type, String label, UpdateFilter toUpdate) { + + String requestJson; + // replace return type + if (type.equals(GraphElementTypeEnum.Node)) { + requestJson = CypherTemplates.CypherUpdateTemplate.replace("$type$", "n"); + } else { + requestJson = CypherTemplates.CypherUpdateTemplate.replace("$type$", "r"); + } + // replace label + if (label != null && !label.isEmpty()) { + requestJson = requestJson.replace("$label$", label); + } else { + requestJson = requestJson.replace("$label$", ""); + } + + // replace filter + if (toUpdate.getProperties().isEmpty()) { + // get all records by label + requestJson = requestJson.replace("{$filter$}", ""); + } else { + String filterStr = CypherTranslator.prepareFilterBody(toUpdate); + requestJson = requestJson.replace("$filter$", filterStr); + } + String props = preparePropertiesInStatement(toUpdate.getToUpdate()); + requestJson = requestJson.replace("$props$", props); + + logger.debug("Try to perform request [ {} ]", requestJson); + + Either<String, Neo4jOperationStatus> result = sendPostCypher(requestJson); + if (result.isRight()) { + return Neo4jOperationStatus.GENERAL_ERROR; + } + return Neo4jOperationStatus.OK; + } + + /** + * + * @param type + * @param label + * @param response + * @return + * @throws ParseException + */ + + private List<GraphElement> parseGetResponse(GraphElementTypeEnum type, String label, String response) + throws ParseException { + List<GraphElement> result = new ArrayList<GraphElement>(); + JSONObject responseData = (JSONObject) jsonParser.parse(response); + JSONArray results = (JSONArray) responseData.get("results"); + Iterator<JSONObject> iteratorResults = results.iterator(); + while (iteratorResults.hasNext()) { + JSONObject elementResult = iteratorResults.next(); + // JSONArray data = (JSONArray) elementResult.get("row"); + JSONArray data = (JSONArray) elementResult.get("data"); + + Iterator<JSONObject> iterator = data.iterator(); + JSONObject element; + while (iterator.hasNext()) { + element = (JSONObject) iterator.next(); + JSONArray row = (JSONArray) element.get("row"); + + Iterator<JSONObject> iteratorRow = row.iterator(); + while (iteratorRow.hasNext()) { + JSONObject rowElement = iteratorRow.next(); + + Map<String, Object> props = new HashMap<String, Object>(); + + for (Map.Entry<String, Object> entry : (Set<Map.Entry<String, Object>>) rowElement.entrySet()) { + // props.put(entry.getKey(), + // rowElement.get(entry.getValue())); + props.put(entry.getKey(), entry.getValue()); + } + GraphElement newElement = GraphElementFactory.createElement(label, type, props); + result.add(newElement); + } + } + } + return result; + } + + private List<List<GraphElement>> parseResult(String response, boolean storeRelationNode) throws ParseException { + + List<List<GraphElement>> batchList = new ArrayList<List<GraphElement>>(); + + JSONObject responseData = (JSONObject) jsonParser.parse(response); + JSONArray results = (JSONArray) responseData.get("results"); + Iterator<JSONObject> iteratorResults = results.iterator(); + + while (iteratorResults.hasNext()) { + JSONObject elementResult = iteratorResults.next(); + JSONArray data = (JSONArray) elementResult.get("data"); + JSONArray columns = (JSONArray) elementResult.get("columns"); + Iterator<JSONObject> iteratorData = data.iterator(); + List<GraphElement> singleDataList = new ArrayList<GraphElement>(); + while (iteratorData.hasNext()) { + + JSONObject singleData = iteratorData.next(); + JSONArray row = (JSONArray) singleData.get("row"); + if (columns.size() == 2) { + // node + JSONArray labelArray = (JSONArray) row.get(1); + JSONObject node = (JSONObject) row.get(0); + + Map<String, Object> props = jsonObjectToMap(node); + // get only first label on node. Now single label supported + GraphElement newElement = GraphElementFactory.createElement((String) labelArray.get(0), + GraphElementTypeEnum.Node, props); + singleDataList.add(newElement); + } + if (columns.size() == 10) { + // relation + JSONObject startNode = (JSONObject) row.get(0); + JSONArray startNodeArray = (JSONArray) row.get(1); + + JSONObject relationFromStart = (JSONObject) row.get(2); + String relationFromStartType = (String) row.get(3); + + JSONObject nodeFrom = (JSONObject) row.get(4); + JSONArray labelFromArray = (JSONArray) row.get(5); + + JSONObject nodeTo = (JSONObject) row.get(6); + JSONArray labelToArray = (JSONArray) row.get(7); + + JSONObject relation = (JSONObject) row.get(8); + String type = (String) row.get(9); + + Map<String, Object> propsStartNode = jsonObjectToMap(startNode); + Map<String, Object> propsRelationStartNode = jsonObjectToMap(relationFromStart); + + Map<String, Object> propsFrom = jsonObjectToMap(nodeFrom); + Map<String, Object> propsTo = jsonObjectToMap(nodeTo); + Map<String, Object> propsRelation = jsonObjectToMap(relation); + + GraphNode startN = (GraphNode) GraphElementFactory.createElement((String) startNodeArray.get(0), + GraphElementTypeEnum.Node, propsStartNode); + + GraphNode from = (GraphNode) GraphElementFactory.createElement((String) labelFromArray.get(0), + GraphElementTypeEnum.Node, propsFrom); + GraphNode to = (GraphNode) GraphElementFactory.createElement((String) labelToArray.get(0), + GraphElementTypeEnum.Node, propsTo); + + singleDataList.add(startN); + + GraphElement relationFromStartNode = GraphElementFactory.createRelation(type, + propsRelationStartNode, startN, from); + singleDataList.add(relationFromStartNode); + + singleDataList.add(from); + singleDataList.add(to); + // get only first type on relationship. Now single type + // supported + GraphElement newElement = GraphElementFactory.createRelation(type, propsRelation, from, to); + singleDataList.add(newElement); + } + if (columns.size() == 8) { + + } + } + batchList.add(singleDataList); + } + return batchList; + } + + private Map<String, Object> jsonObjectToMap(JSONObject node) { + Map<String, Object> props = new HashMap<String, Object>(); + + for (Map.Entry<String, Object> entry : (Set<Map.Entry<String, Object>>) node.entrySet()) { + props.put(entry.getKey(), entry.getValue()); + } + return props; + } + + private String preparePropertiesInStatement(Map<String, Object> properties) { + StringBuilder sb = new StringBuilder(); + int count = 0; + int size = properties.entrySet().size(); + for (Map.Entry<String, Object> entry : properties.entrySet()) { + sb.append("\"").append(entry.getKey()).append("\"").append(":"); + if (entry.getValue() instanceof String) { + sb.append("\""); + } + sb.append(entry.getValue()); + if (entry.getValue() instanceof String) { + sb.append("\""); + } + ++count; + if (count < size) { + sb.append(","); + } + } + return sb.toString(); + } + + private Either<String, Neo4jOperationStatus> createNode(GraphElement element) { + Either<String, Neo4jOperationStatus> status; + if (element instanceof GraphNode) { + GraphNode node = (GraphNode) element; + String json = prepareCreateNodeBody(node); + + logger.debug("Try to save Node [ {} ]", json); + + status = sendPostCypher(json); + + return status; + + } else { + return Either.right(Neo4jOperationStatus.WRONG_INPUT); + } + } + + private Either<String, Neo4jOperationStatus> sendPostCypher(String json) { + Map<String, Object> neo4jParams = ConfigurationManager.getConfigurationManager().getConfiguration().getNeo4j(); + String host = (String) neo4jParams.get("host"); + Integer port = (Integer) neo4jParams.get("port"); + String user = (String) neo4jParams.get("user"); + String password = (String) neo4jParams.get("password"); + + String uri = CypherTemplates.CypherUrlTemplate.replace("$host$", host); + uri = uri.replace("$port$", port.toString()); + + HttpClientContext context = creatClientContext(host, user, password); + CloseableHttpResponse response = null; + + HttpPost post = new HttpPost(uri); + try { + StringEntity input = new StringEntity(json); + input.setContentType("application/json"); + post.setEntity(input); + + response = httpClient.execute(post, context); + + int status = response.getStatusLine().getStatusCode(); + String responseString; + responseString = new BasicResponseHandler().handleResponse(response); + logger.debug("response [ {} ]", responseString); + + if (status == 200 || status == 201) { + logger.debug("cypher request [ {} ]", json); + Neo4jOperationStatus responseStatus = checkResponse(responseString); + if (Neo4jOperationStatus.OK.equals(responseStatus)) { + return Either.left(responseString); + } else { + return Either.right(responseStatus); + } + } else { + logger.debug("cypher request [ {} ] was failed: [ {} ]", json, responseString); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + + } catch (HttpResponseException e) { + logger.debug("failed to perform cypher request [ {} ], {}", json, e); + if (e.getStatusCode() == 401) { + return Either.right(Neo4jOperationStatus.NOT_AUTHORIZED); + } else { + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } + } catch (ClientProtocolException e) { + logger.debug("failed to perform cypher request [ {} ] {}", json, e); + return Either.right(Neo4jOperationStatus.HTTP_PROTOCOL_ERROR); + } catch (IOException e) { + logger.debug("failed to perform cypher request [ {} ] {}", json, e); + return Either.right(Neo4jOperationStatus.NOT_CONNECTED); + } finally { + releaseResource(response); + } + } + + private Neo4jOperationStatus checkResponse(String responseString) { + try { + JSONObject response = (JSONObject) jsonParser.parse(responseString); + JSONArray errors = (JSONArray) response.get("errors"); + if (errors.size() == 0) { + return Neo4jOperationStatus.OK; + } else { + Iterator<JSONObject> iterator = errors.iterator(); + JSONObject error; + while (iterator.hasNext()) { + error = (JSONObject) iterator.next(); + String code = (String) error.get("code"); + String message = (String) error.get("message"); + + Neo4jOperationStatus neoError = mapToNeoError(code, message); + return neoError; + } + return Neo4jOperationStatus.GENERAL_ERROR; + } + } catch (ParseException e) { + logger.error("Failed to parse response", e); + return Neo4jOperationStatus.GENERAL_ERROR; + } + } + + private Neo4jOperationStatus mapToNeoError(String code, String message) { + Neo4jOperationStatus error; + + String[] errorCode = code.split("\\."); + if (errorCode.length < 4) { + error = Neo4jOperationStatus.GENERAL_ERROR; + } else { + // by Classification + switch (errorCode[1]) { + case ClientError: + // by Category + switch (errorCode[2]) { + case General: + error = Neo4jOperationStatus.DB_READ_ONLY; + break; + case LegacyIndex: + error = Neo4jOperationStatus.LEGACY_INDEX_ERROR; + break; + case Request: + error = Neo4jOperationStatus.BAD_REQUEST; + break; + case Schema: + if (errorCode[3].equals(ConstraintViolation)) { + error = Neo4jOperationStatus.ENTITY_ALREADY_EXIST; + } else { + error = Neo4jOperationStatus.SCHEMA_ERROR; + } + break; + case Security: + error = Neo4jOperationStatus.NOT_AUTHORIZED; + break; + case Statement: + // by Title + if (errorCode[3].equals(EntityNotFound)) { + error = Neo4jOperationStatus.NOT_FOUND; + } else { + if (errorCode[3].equals(ConstraintViolation)) { + error = Neo4jOperationStatus.ENTITY_ALREADY_EXIST; + } else { + error = Neo4jOperationStatus.BAD_REQUEST; + } + } + break; + case Transaction: + error = Neo4jOperationStatus.TRANSACTION_ERROR; + break; + default: + error = Neo4jOperationStatus.GENERAL_ERROR; + break; + } + break; + case DatabaseError: + // by Category + switch (errorCode[2]) { + case General: + error = Neo4jOperationStatus.GENERAL_ERROR; + break; + case Schema: + error = Neo4jOperationStatus.SCHEMA_ERROR; + break; + case Statement: + error = Neo4jOperationStatus.EXECUTION_FAILED; + break; + case Transaction: + error = Neo4jOperationStatus.TRANSACTION_ERROR; + break; + default: + error = Neo4jOperationStatus.GENERAL_ERROR; + break; + } + break; + case TransientError: + error = Neo4jOperationStatus.DB_NOT_AVAILABLE; + break; + default: + error = Neo4jOperationStatus.GENERAL_ERROR; + break; + } + error.setOriginError(code).setMessage(message); + String errorFromCfg = code.replace(".", "_"); + String helpMessage = ConfigurationManager.getConfigurationManager().getNeo4jErrorsConfiguration() + .getErrorMessage(errorFromCfg); + if (helpMessage != null && !helpMessage.isEmpty()) { + error.setHelpErrorMsg(helpMessage); + } + } + return error; + } + + private String prepareCreateNodeBody(GraphNode node) { + + String body = CypherTemplates.CypherCreateNodeTemplate.replace("$label$", node.getLabel()); + + body = body.replace("$props$", DaoUtils.convertToJson(node.toGraphMap())); + + return body; + } + + /** + * the method returns all the indexes for the given label if no label is + * supplied ( null or "") all indexes will be returned + * + * @param label + * the name of the label + * @param ip + * @param user + * @param password + * @return a map of labels and there properties + */ + public Either<Map<String, List<String>>, Neo4jOperationStatus> getIndexes(String label) { + Map<String, Object> neo4jParams = ConfigurationManager.getConfigurationManager().getConfiguration().getNeo4j(); + String host = (String) neo4jParams.get("host"); + Integer port = (Integer) neo4jParams.get("port"); + String user = (String) neo4jParams.get("user"); + String password = (String) neo4jParams.get("password"); + + String uri = null; + if (label == null || "".equals(label)) { + uri = CypherTemplates.getAllIndexsTemplate.replace("$host$", host); + } else { + uri = CypherTemplates.getAllIndexsTemplate.replace("$host$", host) + "/" + label; + } + uri = uri.replace("$port$", port.toString()); + + HttpClientContext context = creatClientContext(host, user, password); + CloseableHttpResponse response = null; + + HttpGet get = new HttpGet(uri); + get.setHeader("Content-Type", "application/json"); + get.setHeader("Accept", "application/json; charset=UTF-8"); + + try { + + response = httpClient.execute(get, context); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + logger.error("failed to get indexes requeste returned " + statusCode); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } else { + Map<String, List<String>> labels = getLeablesFromJson(response); + return Either.left(labels); + } + } catch (Exception e) { + logger.debug("failed to get indexes ", e); + return Either.right(Neo4jOperationStatus.GENERAL_ERROR); + } finally { + releaseResource(response); + + } + + } + + private Map<String, List<String>> getLeablesFromJson(CloseableHttpResponse response) + throws HttpResponseException, IOException, ParseException { + Map<String, List<String>> labels = new HashMap<>(); + String responseString = new BasicResponseHandler().handleResponse(response); + JSONArray results = (JSONArray) jsonParser.parse(responseString); + Iterator<JSONObject> iteratorResults = results.iterator(); + while (iteratorResults.hasNext()) { + JSONObject elementResult = iteratorResults.next(); + String label = (String) elementResult.get("label"); + List<String> props = labels.get(label); + if (props == null) { + props = new ArrayList<>(); + labels.put(label, props); + } + JSONArray properties = (JSONArray) elementResult.get("property_keys"); + Iterator<String> iterator = properties.iterator(); + while (iterator.hasNext()) { + props.add(iterator.next()); + } + } + return labels; + } + + public Neo4jOperationStatus createIndex(String label, List<String> propertyNames) { + + Neo4jOperationStatus result = Neo4jOperationStatus.OK; + if (propertyNames != null && !propertyNames.isEmpty()) { + + Map<String, Object> neo4jParams = ConfigurationManager.getConfigurationManager().getConfiguration() + .getNeo4j(); + String host = (String) neo4jParams.get("host"); + Integer port = (Integer) neo4jParams.get("port"); + String user = (String) neo4jParams.get("user"); + String password = (String) neo4jParams.get("password"); + + String uri = CypherTemplates.batchTemplate.replace("$host$", host); + uri = uri.replace("$port$", port.toString()); + + String opertionUri = "/schema/index/" + label; + + HttpClientContext context = creatClientContext(host, user, password); + + CloseableHttpResponse response = null; + + HttpPost post = new HttpPost(uri); + + String json = createBatchJson(HttpMethod.POST, opertionUri, propertyNames); + + try { + StringEntity input = new StringEntity(json); + input.setContentType("application/json"); + post.setEntity(input); + response = httpClient.execute(post, context); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + logger.error("failed to create index for label [" + label + "] with properties:" + propertyNames + + " requeste returned " + statusCode); + result = Neo4jOperationStatus.GENERAL_ERROR; + } else { + logger.debug("index for label [ {} ] with properties {} created", label, propertyNames); + } + } catch (Exception e) { + logger.debug("failed to create index for label [ {} ] with properties {}", label, propertyNames); + result = Neo4jOperationStatus.GENERAL_ERROR; + } finally { + + releaseResource(response); + + } + + } + + else { + logger.debug("no index was created for label: {}, the received propertyNames list: {} is invalid", label, propertyNames); + return Neo4jOperationStatus.WRONG_INPUT; + } + + return result; + } + + public Neo4jOperationStatus createUniquenessConstraints(String label, List<String> propertyNames) { + Neo4jOperationStatus result = Neo4jOperationStatus.OK; + if (propertyNames != null && !propertyNames.isEmpty()) { + + Map<String, Object> neo4jParams = ConfigurationManager.getConfigurationManager().getConfiguration() + .getNeo4j(); + String host = (String) neo4jParams.get("host"); + Integer port = (Integer) neo4jParams.get("port"); + String user = (String) neo4jParams.get("user"); + String password = (String) neo4jParams.get("password"); + + String uri = CypherTemplates.batchTemplate.replace("$host$", host); + uri = uri.replace("$port$", port.toString()); + + String opertionUri = "/schema/constraint/" + label + "/uniqueness/"; + + HttpClientContext context = creatClientContext(host, user, password); + + CloseableHttpResponse response = null; + + HttpPost post = new HttpPost(uri); + + String json = createBatchJson(HttpMethod.POST, opertionUri, propertyNames); + + try { + StringEntity input = new StringEntity(json); + input.setContentType("application/json"); + post.setEntity(input); + response = httpClient.execute(post, context); + + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + logger.error("failed to create uniqueness constraint for label [" + label + "] on properties:" + + propertyNames + ". request returned " + statusCode); + result = Neo4jOperationStatus.GENERAL_ERROR; + } else { + logger.debug("uniqueness constraint for label [ {} ] on properties {} created", label, propertyNames); + } + } catch (Exception e) { + logger.error("failed to create uniqueness constraint [ {} ] with properties {}, error: {}",label, propertyNames, e); + result = Neo4jOperationStatus.GENERAL_ERROR; + } finally { + releaseResource(response); + } + + } + + else { + logger.debug("no index was created for label: {} the received propertyNames list: {} is invalid", label, propertyNames); + return Neo4jOperationStatus.WRONG_INPUT; + } + + return result; + } + + public Neo4jOperationStatus deleteElement(GraphElementTypeEnum type, String label, MatchFilter filter) { + + String requestJson; + // replace return type + if (type.equals(GraphElementTypeEnum.Node)) { + logger.debug("removing node label: {}", label); + requestJson = createDeleteNodeStatment(label, filter); + + } else { + logger.error(" delete on type {} is not yet supported", type); + throw new RuntimeException(" delete on type " + type + " is not yet supported"); + } + + logger.debug("Try to perform request [ {} ]", requestJson); + + Either<String, Neo4jOperationStatus> status = sendPostCypher(requestJson); + if (status.isRight()) { + logger.error(" delete request failed with {}", status.right()); + return Neo4jOperationStatus.GENERAL_ERROR; + } else { + return Neo4jOperationStatus.OK; + } + } + + public String getNeo4jVersion() throws Exception { + Map<String, Object> neo4jParams = ConfigurationManager.getConfigurationManager().getConfiguration().getNeo4j(); + String host = (String) neo4jParams.get("host"); + Integer port = (Integer) neo4jParams.get("port"); + String user = (String) neo4jParams.get("user"); + String password = (String) neo4jParams.get("password"); + + String uri = getServiceRoot.replace("$host$", host).replace("$port$", port.toString()); + + HttpClientContext context = creatClientContext(host, user, password); + CloseableHttpResponse response = null; + String result = null; + + HttpGet get = new HttpGet(uri); + get.setHeader("Content-Type", "application/json"); + get.setHeader("Accept", "application/json; charset=UTF-8"); + + try { + response = httpClient.execute(get, context); + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != 200) { + throw new Exception("Couldn't get Neo4j service root, HTTP status " + statusCode); + } else { + // Parse response + String responseString = new BasicResponseHandler().handleResponse(response); + JSONObject responseData = (JSONObject) jsonParser.parse(responseString); + Object obj = responseData.get("neo4j_version"); + if (obj != null) { + result = (String) obj; + } + return result; + } + } finally { + releaseResource(response); + } + } + + private String createDeleteNodeStatment(String label, MatchFilter filter) { + String requestJson; + requestJson = CypherTemplates.CypherDeleteNodeTemplate; + + if (label != null && !label.isEmpty()) { + requestJson = requestJson.replace("$label$", label); + } else { + requestJson = requestJson.replace("$label$", ""); + } + + // replace filter + if (filter.getProperties().isEmpty()) { + // get all records by label + requestJson = requestJson.replace("{$filter$}", ""); + } else { + String filterStr = CypherTranslator.prepareFilterBody(filter); + requestJson = requestJson.replace("$filter$", filterStr); + } + return requestJson; + } + + /* + * removed do to fortify scan CredentialsProvider cp = new + * BasicCredentialsProvider(); cp.setCredentials(AuthScope.ANY, new + * UsernamePasswordCredentials(user, password)); AuthCache authCache = new + * BasicAuthCache(); BasicScheme basicAuth = new BasicScheme(); + * authCache.put(new HttpHost(ip, 7474, "http"), basicAuth); + * context.setAuthCache(authCache); context.setCredentialsProvider(cp); + * + */ + private HttpClientContext creatClientContext(String ip, String user, String password) { + HttpClientContext context = HttpClientContext.create(); + + return context; + } + + private void releaseResource(CloseableHttpResponse response) { + if (response != null) { + try { + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + response.close(); + } catch (Exception e) { + logger.error("failed to close connection exception", e); + } + } + } + + private String createBatchJson(HttpMethod method, String opertionUri, List<String> propertyNames) { + StringBuilder sb = new StringBuilder(); + sb.append("[ "); + for (int i = 0; i < propertyNames.size(); i++) { + sb.append("{ \"method\" : \"" + method + "\" , \"to\" : \"" + opertionUri + + "\" , \"body\" : { \"property_keys\" : [ \"" + propertyNames.get(i) + "\" ] } }"); + if (i + 1 < propertyNames.size()) { + sb.append(","); + } + } + sb.append(" ]"); + String json = sb.toString(); + return json; + } + + enum HttpMethod { + GET, PUT, POST, DELETE + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jEdge.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jEdge.java new file mode 100644 index 0000000000..e8278a9a3e --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jEdge.java @@ -0,0 +1,69 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.Map; + +import org.openecomp.sdc.be.dao.graph.datatype.ActionEnum; + +public class Neo4jEdge { + + private GraphEdgeLabels edgeType; + private Map<String, Object> properties; + private ActionEnum action; + + public Neo4jEdge(GraphEdgeLabels edgeType, Map<String, Object> properties, ActionEnum actionEnum) { + super(); + this.edgeType = edgeType; + this.properties = properties; + this.action = actionEnum; + } + + public GraphEdgeLabels getEdgeType() { + return edgeType; + } + + public void setEdgeType(GraphEdgeLabels edgeType) { + this.edgeType = edgeType; + } + + public Map<String, Object> getProperties() { + return properties; + } + + public void setProperties(Map<String, Object> properties) { + this.properties = properties; + } + + public ActionEnum getAction() { + return action; + } + + public void setAction(ActionEnum action) { + this.action = action; + } + + @Override + public String toString() { + return "Neo4jEdge [edgeType=" + edgeType + ", properties=" + properties + ", action=" + action + "]"; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jGraphBatchBuilder.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jGraphBatchBuilder.java new file mode 100644 index 0000000000..831fb001be --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jGraphBatchBuilder.java @@ -0,0 +1,194 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.openecomp.sdc.be.dao.graph.datatype.ActionEnum; +import org.openecomp.sdc.be.dao.graph.datatype.GraphElement; +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; +import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation; +import org.openecomp.sdc.be.dao.graph.datatype.RelationEndPoint; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import fj.data.Either; + +public class Neo4jGraphBatchBuilder { + + private static Logger logger = LoggerFactory.getLogger(Neo4jGraphBatchBuilder.class.getName()); + + public Either<BatchBuilder, Neo4jOperationStatus> buildBatchBuilderFromTable( + GraphNeighbourTable graphNeighbourTable) { + + logger.debug("The table sent in order to build BatchBuilder is {}", graphNeighbourTable); + + List<GraphNode> nodes = graphNeighbourTable.getNodes(); + if (nodes != null && nodes.size() > 0) { + // String resourceId = findResourceDataIdFromNodes(nodes); + // if (resourceId == null || resourceId.isEmpty()) { + // logger.error("Cannot find resource id in the graph table"); + // return Either.right(ActionStatus.INVALID_CONTENT); + // } + List<NodeRelation> directedEdges = graphNeighbourTable.getDirectedEdges(); + + List<RelationEndPoint> relationEndPoints = new ArrayList<RelationEndPoint>(nodes.size()); + Set<Integer> nodesInRelations = findDistinctNodesIndex(directedEdges); + + buildRelationEndPoints(nodes, nodesInRelations, relationEndPoints); + + BatchBuilder batchBuilder = BatchBuilder.getBuilder(); + + for (GraphElement neo4jElement : nodes) { + if (neo4jElement.getAction() != ActionEnum.Delete) { + logger.debug("Goint to add node {} to batch builder.", neo4jElement); + batchBuilder.add(neo4jElement); + } + } + + if (directedEdges != null) { + for (NodeRelation nodeRelation : directedEdges) { + GraphRelation relation = buildNeo4jRelation(relationEndPoints, nodeRelation); + logger.debug("Goint to add relation {} to catch builder.", relation); + batchBuilder.add(relation); + } + } + + for (GraphElement neo4jElement : nodes) { + if (neo4jElement.getAction() == ActionEnum.Delete) { + logger.debug("Goint to add node {} to batch builder.", neo4jElement); + batchBuilder.add(neo4jElement); + } + } + + return Either.left(batchBuilder); + + } else { + logger.error("No node was sent in order to create the resource."); + return Either.right(Neo4jOperationStatus.BAD_REQUEST); + } + } + + private Pair<String, String> getUniqueIdKeyValue(GraphNode neo4jNode) { + + // String label = neo4jNode.getLabel(); + // NodeTypeEnum nodeTypeEnum = NodeTypeEnum.getByName(label); + // + return Pair.createPair(neo4jNode.getUniqueIdKey(), neo4jNode.getUniqueId().toString()); + } + + private Set<Integer> findDistinctNodesIndex(List<NodeRelation> directedEdges) { + + HashSet<Integer> nodesIndex = new HashSet<Integer>(); + + if (directedEdges != null) { + for (NodeRelation nodeRelation : directedEdges) { + nodesIndex.add(nodeRelation.getFromIndex()); + nodesIndex.add(nodeRelation.getToIndex()); + } + } + + return nodesIndex; + } + + private String findResourceDataIdFromNodes(List<GraphNode> nodes) { + + if (nodes != null) { + + for (GraphNode neo4jNode : nodes) { + String label = neo4jNode.getLabel(); + if (label.equals(NodeTypeEnum.Resource.getName())) { + return neo4jNode.getUniqueId().toString(); + } + } + } + + return null; + } + + private GraphRelation buildNeo4jRelation(List<RelationEndPoint> relationEndPoints, NodeRelation nodeRelation) { + GraphRelation relation = new GraphRelation(); + int fromIndex = nodeRelation.getFromIndex(); + int toIndex = nodeRelation.getToIndex(); + Neo4jEdge neo4jEdge = nodeRelation.getEdge(); + relation.setFrom(relationEndPoints.get(fromIndex)); + relation.setTo(relationEndPoints.get(toIndex)); + relation.setType(neo4jEdge.getEdgeType().getProperty()); + + // TODO: fix it after change + Map<String, Object> edgeProps = neo4jEdge.getProperties(); + if (edgeProps != null && false == edgeProps.isEmpty()) { + relation.addPropertis(edgeProps); + } + + relation.setAction(neo4jEdge.getAction()); + return relation; + } + + private void buildRelationEndPoints(List<GraphNode> nodes, Set<Integer> nodesInRelations, + List<RelationEndPoint> relationEndPoints) { + + if (nodesInRelations != null) { + for (Integer nodeIndex : nodesInRelations) { + + GraphElement neo4jElement = nodes.get(nodeIndex); + GraphNode neo4jNode = (GraphNode) neo4jElement; + String label = neo4jNode.getLabel(); + Pair<String, String> uniqueKeyValue = getUniqueIdKeyValue(neo4jNode); + + RelationEndPoint endPoint = new RelationEndPoint(NodeTypeEnum.getByName(label), uniqueKeyValue.getKey(), + uniqueKeyValue.getValue()); + relationEndPoints.add(nodeIndex, endPoint); + + } + } + + } + + public static class Pair<K, V> { + + private final K key; + private final V value; + + public static <K, V> Pair<K, V> createPair(K key, V value) { + return new Pair<K, V>(key, value); + } + + public Pair(K key, V value) { + this.key = key; + this.value = value; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + + } +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jOperationStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jOperationStatus.java new file mode 100644 index 0000000000..154449b521 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/Neo4jOperationStatus.java @@ -0,0 +1,77 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +public enum Neo4jOperationStatus { + + OK, NOT_CONNECTED, NOT_AUTHORIZED, HTTP_PROTOCOL_ERROR, DB_NOT_AVAILABLE, DB_READ_ONLY, BAD_REQUEST, LEGACY_INDEX_ERROR, SCHEMA_ERROR, TRANSACTION_ERROR, EXECUTION_FAILED, ENTITY_ALREADY_EXIST, + + WRONG_INPUT, GENERAL_ERROR, NOT_SUPPORTED, NOT_FOUND; + + private String originError; + private String message; + private String helpErrorMsg; + + private static final String NA = "NA"; + + Neo4jOperationStatus() { + originError = NA; + message = NA; + helpErrorMsg = NA; + } + + public Neo4jOperationStatus setOriginError(String originError) { + this.originError = originError; + return this; + } + + public Neo4jOperationStatus setMessage(String message) { + if (message != null && !message.isEmpty()) { + this.message = message; + } + return this; + } + + public Neo4jOperationStatus setHelpErrorMsg(String helpErrorMsg) { + this.helpErrorMsg = helpErrorMsg; + return this; + } + + public String getOriginError() { + return originError; + } + + public String getMessage() { + return message; + } + + public String getHelpErrorMsg() { + return helpErrorMsg; + } + + public String printError() { + StringBuilder sb = new StringBuilder(); + sb.append("[").append(toString()).append("-").append(originError).append("-").append(helpErrorMsg).append("-") + .append(message).append("]"); + return sb.toString(); + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/NodeRelation.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/NodeRelation.java new file mode 100644 index 0000000000..c1402f402f --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/NodeRelation.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j; + +public class NodeRelation { + + private int fromIndex; + private int toIndex; + private Neo4jEdge edge; + + public NodeRelation(int fromIndex, int toIndex, Neo4jEdge edge) { + super(); + this.fromIndex = fromIndex; + this.toIndex = toIndex; + this.edge = edge; + } + + public int getFromIndex() { + return fromIndex; + } + + public void setFromIndex(int fromIndex) { + this.fromIndex = fromIndex; + } + + public int getToIndex() { + return toIndex; + } + + public void setToIndex(int toIndex) { + this.toIndex = toIndex; + } + + public Neo4jEdge getEdge() { + return edge; + } + + public void setEdge(Neo4jEdge edge) { + this.edge = edge; + } + + @Override + public String toString() { + return "NodeRelation [fromIndex=" + fromIndex + ", toIndex=" + toIndex + ", edge=" + edge + "]"; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/MatchFilter.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/MatchFilter.java new file mode 100644 index 0000000000..10e93c1f56 --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/MatchFilter.java @@ -0,0 +1,51 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j.filters; + +import java.util.HashMap; +import java.util.Map; + +public class MatchFilter { + private Map<String, Object> toMatchProperties; + + public MatchFilter() { + toMatchProperties = new HashMap<String, Object>(); + } + + public MatchFilter(Map<String, Object> toMatchProperties) { + super(); + this.toMatchProperties = toMatchProperties; + } + + public Map<String, Object> getProperties() { + return toMatchProperties; + } + + public void setProperties(Map<String, Object> properties) { + this.toMatchProperties = properties; + } + + public MatchFilter addToMatch(String propName, Object value) { + toMatchProperties.put(propName, value); + return this; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveByRelationFilter.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveByRelationFilter.java new file mode 100644 index 0000000000..698077d45b --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveByRelationFilter.java @@ -0,0 +1,81 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j.filters; + +import org.openecomp.sdc.be.dao.graph.datatype.GraphNode; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; + +public class RecursiveByRelationFilter extends RecursiveFilter { + + private GraphNode node; + private String relationType; + + public RecursiveByRelationFilter() { + super(); + } + + public RecursiveByRelationFilter(NodeTypeEnum nodeType, GraphNode node) { + super(nodeType); + this.node = node; + } + + public RecursiveByRelationFilter(NodeTypeEnum nodeType) { + super(nodeType); + } + + public RecursiveByRelationFilter(NodeTypeEnum nodeType, GraphNode node, String relationType) { + super(nodeType); + this.node = node; + this.relationType = relationType; + } + + public RecursiveByRelationFilter addNode(GraphNode node) { + this.node = node; + return this; + } + + public RecursiveByRelationFilter addRelation(String relationType) { + this.relationType = relationType; + return this; + } + + public GraphNode getNode() { + return node; + } + + public void setNode(GraphNode node) { + this.node = node; + } + + public String getRelationType() { + return relationType; + } + + public void setRelationType(String relationType) { + this.relationType = relationType; + } + + @Override + public String toString() { + return "RecursiveByRelationFilter [node=" + node + ", relationType=" + relationType + "]"; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveFilter.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveFilter.java new file mode 100644 index 0000000000..fa78539f8f --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/RecursiveFilter.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j.filters; + +import java.util.ArrayList; +import java.util.List; + +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; + +public class RecursiveFilter extends MatchFilter { + + private List<String> childRelationTypes; + NodeTypeEnum nodeType; + + public RecursiveFilter() { + childRelationTypes = new ArrayList<String>(); + } + + public RecursiveFilter(NodeTypeEnum nodeType) { + childRelationTypes = new ArrayList<String>(); + this.nodeType = nodeType; + } + + public RecursiveFilter addChildRelationType(String type) { + childRelationTypes.add(type); + return this; + } + + public List<String> getChildRelationTypes() { + return childRelationTypes; + } + + public void setChildRelationTypes(List<String> childRelationTypes) { + this.childRelationTypes = childRelationTypes; + } + + public NodeTypeEnum getNodeType() { + return nodeType; + } + + public void setNodeType(NodeTypeEnum nodeType) { + this.nodeType = nodeType; + } + + @Override + public String toString() { + return "RecursiveFilter [childRelationTypes=" + childRelationTypes + ", nodeType=" + nodeType + "]"; + } + +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/UpdateFilter.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/UpdateFilter.java new file mode 100644 index 0000000000..3abfdeb70e --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/neo4j/filters/UpdateFilter.java @@ -0,0 +1,56 @@ +/*- + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2017 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========================================================= + */ + +package org.openecomp.sdc.be.dao.neo4j.filters; + +import java.util.HashMap; +import java.util.Map; + +public class UpdateFilter extends MatchFilter { + + private Map<String, Object> toUpdate; + + public UpdateFilter(Map<String, Object> toUpdate) { + super(); + this.toUpdate = toUpdate; + } + + public UpdateFilter() { + super(); + toUpdate = new HashMap<String, Object>(); + } + + public UpdateFilter(Map<String, Object> toMatch, Map<String, Object> toUpdate) { + super(toMatch); + this.toUpdate = toUpdate; + } + + public Map<String, Object> getToUpdate() { + return toUpdate; + } + + public void setToUpdate(Map<String, Object> toUpdate) { + this.toUpdate = toUpdate; + } + + public void addToUpdate(String property, Object value) { + toUpdate.put(property, value); + } +} |