diff options
5 files changed, 1561 insertions, 1378 deletions
diff --git a/aai-traversal/src/main/java/org/onap/aai/dbgraphmap/SearchGraph.java b/aai-traversal/src/main/java/org/onap/aai/dbgraphmap/SearchGraph.java index 0221d8a..a8f0153 100644 --- a/aai-traversal/src/main/java/org/onap/aai/dbgraphmap/SearchGraph.java +++ b/aai-traversal/src/main/java/org/onap/aai/dbgraphmap/SearchGraph.java @@ -37,6 +37,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilderException; import javax.xml.bind.JAXBException; +import org.apache.commons.lang3.StringUtils; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; @@ -75,7 +76,7 @@ import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.exceptions.AAIFormatVertexException; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersions; -import org.onap.aai.util.StoreNotificationEvent; +import org.onap.aai.util.NodesQueryBuilder; import org.springframework.beans.factory.annotation.Autowired; import com.att.eelf.configuration.EELFLogger; @@ -86,1068 +87,1065 @@ import edu.emory.mathcs.backport.java.util.Collections; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import com.jcabi.log.Logger; +import org.onap.aai.util.GenericQueryBuilder; -/** - * Database Mapping class which acts as the middle man between the REST interface objects - * for the Search namespace +/** + * Database Mapping class which acts as the middle man between the REST interface objects for the + * Search namespace + * */ public class SearchGraph { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchGraph.class); - - private LoaderFactory loaderFactory; - - private EdgeIngestor edgeIngestor; - - private SchemaVersions schemaVersions; - - @Autowired - public SearchGraph(LoaderFactory loaderFactory, EdgeIngestor edgeIngestor, SchemaVersions schemaVersions){ - this.loaderFactory = loaderFactory; - this.edgeIngestor = edgeIngestor; - this.schemaVersions = schemaVersions; - } - /** - * Get the search result based on the includeNodeType and depth provided. - * - * @param fromAppId the from app id - * @param transId the trans id - * @param startNodeType the start node type - * @param startNodeKeyParams the start node key params - * @param includeNodeTypes the include node types - * @param depth the depth - * @param aaiExtMap the aai ext map - * @return Response - * @throws AAIException the AAI exception - */ - public Response runGenericQuery ( - HttpHeaders headers, - String startNodeType, - List <String> startNodeKeyParams, - List <String> includeNodeTypes, - final int depth, - TransactionalGraphEngine dbEngine, - Loader loader, - UrlBuilder urlBuilder) throws AAIException { - Response response = null; - boolean success = true; - String result = ""; - try { - dbEngine.startTransaction(); - - if( startNodeType == null ){ - throw new AAIException("AAI_6120", "null start-node-type passed to the generic query"); - } - - if( startNodeKeyParams == null ){ - throw new AAIException("AAI_6120", "no key param passed to the generic query"); - } - - if( includeNodeTypes == null ){ - throw new AAIException("AAI_6120", "no include params passed to the generic query"); - } - - if (depth > 6) { - throw new AAIException("AAI_6120", "The maximum depth supported by the generic query is 6"); - } - final QueryBuilder queryBuilder; - - // there is an issue with service-instance - it is a unique node but still dependent - // for now query it directly without attempting to craft a valid URI - if (startNodeType.equalsIgnoreCase("service-instance") && startNodeKeyParams.size() == 1) { - Introspector obj = loader.introspectorFromName(startNodeType); - // Build a hash with keys to uniquely identify the start Node - String keyName = null; - String keyValue = null; - - QueryBuilder builder = dbEngine.getQueryBuilder().getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, "service-instance"); - for( String keyData : startNodeKeyParams ){ - int colonIndex = keyData.indexOf(":"); - if( colonIndex <= 0 ){ - throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]"); - } - else { - keyName = keyData.substring(0, colonIndex).split("\\.")[1]; - keyValue = keyData.substring(colonIndex + 1); - builder.getVerticesByProperty(keyName, keyValue); - } - } - - queryBuilder = builder; - } else { - URI uri = craftUriFromQueryParams(loader, startNodeType, startNodeKeyParams); - queryBuilder = dbEngine.getQueryBuilder().createQueryFromURI(uri).getQueryBuilder(); - } - List<Vertex> results = queryBuilder.toList(); - if( results.isEmpty()){ - throw new AAIException("AAI_6114", "No Node of type " + - startNodeType + - " found for properties: " + - startNodeKeyParams.toString()); - } else if (results.size() > 1) { - String detail = "More than one Node found by getUniqueNode for params: " + startNodeKeyParams.toString() + "\n"; - throw new AAIException("AAI_6112", detail); - } - - Vertex startNode = results.get(0); - - Collection <Vertex> ver = new HashSet <>(); - List<Vertex> queryResults = new ArrayList<>(); - GraphTraversalSource traversalSource = dbEngine.asAdmin().getReadOnlyTraversalSource(); - GraphTraversal<Vertex, Vertex> traversal; - if (includeNodeTypes.contains(startNodeType) || depth == 0 || includeNodeTypes.contains("all") ) - ver.add(startNode); - - // Now look for a node of includeNodeType within a given depth - traversal = traversalSource.withSideEffect("x", ver).V(startNode) - .times(depth).repeat(__.both().store("x")).cap("x").unfold(); - - if (!includeNodeTypes.contains("all")) { - traversal.where(__.has(AAIProperties.NODE_TYPE, P.within(includeNodeTypes))); - } - queryResults = traversal.toList(); - - - if( queryResults.isEmpty()){ - LOGGER.warn("No nodes found - apipe was null/empty"); - } - else { - - Introspector searchResults = createSearchResults(loader, urlBuilder, queryResults); - - String outputMediaType = getMediaType(headers.getAcceptableMediaTypes()); - org.onap.aai.introspection.MarshallerProperties properties = new org.onap.aai.introspection.MarshallerProperties.Builder( - org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build(); - - result = searchResults.marshal(properties); - response = Response.ok().entity(result).build(); - - LOGGER.debug(ver.size() + " node(s) traversed, " + queryResults.size() + " found"); - } - success = true; - } catch (AAIException e) { - success = false; - throw e; - } catch (Exception e) { - success = false; - throw new AAIException("AAI_5105", e); - } finally { - if (dbEngine != null) { - if (success) { - dbEngine.commit(); - } else { - dbEngine.rollback(); - } - } - - } - - return response; - } - - private URI craftUriFromQueryParams(Loader loader, String startNodeType, List<String> startNodeKeyParams) throws UnsupportedEncodingException, IllegalArgumentException, UriBuilderException, AAIException { - Introspector relationship = loader.introspectorFromName("relationship"); - - relationship.setValue("related-to", startNodeType); - List<Object> relationshipDataList = relationship.getValue("relationship-data"); - - for( String keyData : startNodeKeyParams ){ - int colonIndex = keyData.indexOf(":"); - if( colonIndex <= 0 ){ - throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]"); - } - else { - Introspector data = loader.introspectorFromName("relationship-data"); - data.setValue("relationship-key", keyData.substring(0, colonIndex)); - data.setValue("relationship-value", keyData.substring(colonIndex + 1)); - relationshipDataList.add(data.getUnderlyingObject()); - } - } - - RelationshipToURI parser = new RelationshipToURI(loader, relationship); - - return parser.getUri(); - } - - /** - * Run nodes query. - * - * @param fromAppId the from app id - * @param transId the trans id - * @param targetNodeType the target node type - * @param edgeFilterParams the edge filter params - * @param filterParams the filter params - * @param aaiExtMap the aai ext map - * @return Response - * @throws AAIException the AAI exception - */ - public Response runNodesQuery ( - HttpHeaders headers, - String targetNodeType, - List <String> edgeFilterParams, - List <String> filterParams, - TransactionalGraphEngine dbEngine, - Loader loader, - UrlBuilder urlBuilder) throws AAIException { - - Response response = null; - boolean success = true; + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchGraph.class); + + private LoaderFactory loaderFactory; + + private EdgeIngestor edgeIngestor; + + private SchemaVersions schemaVersions; + + @Autowired + public SearchGraph(LoaderFactory loaderFactory, EdgeIngestor edgeIngestor, SchemaVersions schemaVersions) { + this.loaderFactory = loaderFactory; + this.edgeIngestor = edgeIngestor; + this.schemaVersions = schemaVersions; + } + + /** + * Get the search result based on the includeNodeType and depth provided. + * + * @param genericQueryBuilder + */ + public Response runGenericQuery(GenericQueryBuilder genericQueryBuilder) throws AAIException { + Response response = null; + boolean success = true; + String result = ""; + try { + genericQueryBuilder.getDbEngine().startTransaction(); + + if (genericQueryBuilder.getStartNodeType() == null) { + throw new AAIException("AAI_6120", "null start-node-type passed to the generic query"); + } + + if (genericQueryBuilder.getStartNodeKeyParams() == null) { + throw new AAIException("AAI_6120", "no key param passed to the generic query"); + } + + if (genericQueryBuilder.getIncludeNodeTypes() == null) { + throw new AAIException("AAI_6120", "no include params passed to the generic query"); + } + + if (genericQueryBuilder.getDepth() > 6) { + throw new AAIException("AAI_6120", "The maximum depth supported by the generic query is 6"); + } + final QueryBuilder queryBuilder; + + // there is an issue with service-instance - it is a unique node but still dependent + // for now query it directly without attempting to craft a valid URI + if (genericQueryBuilder.getStartNodeType().equalsIgnoreCase("service-instance") + && genericQueryBuilder.getStartNodeKeyParams().size() == 1) { + Introspector obj = + genericQueryBuilder.getLoader().introspectorFromName(genericQueryBuilder.getStartNodeType()); + // Build a hash with keys to uniquely identify the start Node + String keyName = null; + String keyValue = null; + + QueryBuilder builder = genericQueryBuilder.getDbEngine().getQueryBuilder() + .getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, "service-instance"); + for (String keyData : genericQueryBuilder.getStartNodeKeyParams()) { + int colonIndex = keyData.indexOf(":"); + if (colonIndex <= 0) { + throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]"); + } else { + keyName = keyData.substring(0, colonIndex).split("\\.")[1]; + keyValue = keyData.substring(colonIndex + 1); + builder.getVerticesByProperty(keyName, keyValue); + } + } + + queryBuilder = builder; + } else { + URI uri = craftUriFromQueryParams(genericQueryBuilder.getLoader(), + genericQueryBuilder.getStartNodeType(), genericQueryBuilder.getStartNodeKeyParams()); + queryBuilder = + genericQueryBuilder.getDbEngine().getQueryBuilder().createQueryFromURI(uri).getQueryBuilder(); + } + List<Vertex> results = queryBuilder.toList(); + if (results.isEmpty()) { + String errorMessage = String.format("No Node of type %s ", genericQueryBuilder.getStartNodeType(), + " found for properties: %s", genericQueryBuilder.getStartNodeKeyParams().toString()); + throw new AAIException("AAI_6114", errorMessage); + } else if (results.size() > 1) { + String detail = "More than one Node found by getUniqueNode for params: " + + genericQueryBuilder.getStartNodeKeyParams().toString() + "\n"; + throw new AAIException("AAI_6112", detail); + } + + Vertex startNode = results.get(0); + + Collection<Vertex> ver = new HashSet<>(); + List<Vertex> queryResults = new ArrayList<>(); + GraphTraversalSource traversalSource = + genericQueryBuilder.getDbEngine().asAdmin().getReadOnlyTraversalSource(); + GraphTraversal<Vertex, Vertex> traversal; + if (genericQueryBuilder.getIncludeNodeTypes().contains(genericQueryBuilder.getStartNodeType()) + || genericQueryBuilder.getDepth() == 0 || genericQueryBuilder.getIncludeNodeTypes().contains("all")) + ver.add(startNode); + + // Now look for a node of includeNodeType within a given depth + traversal = traversalSource.withSideEffect("x", ver).V(startNode).times(genericQueryBuilder.getDepth()) + .repeat(__.both().store("x")).cap("x").unfold(); + + if (!genericQueryBuilder.getIncludeNodeTypes().contains("all")) { + traversal.where(__.has(AAIProperties.NODE_TYPE, P.within(genericQueryBuilder.getIncludeNodeTypes()))); + } + queryResults = traversal.toList(); + + + if (queryResults.isEmpty()) { + LOGGER.warn("No nodes found - apipe was null/empty"); + } else { + + Introspector searchResults = createSearchResults(genericQueryBuilder.getLoader(), + genericQueryBuilder.getUrlBuilder(), queryResults); + + String outputMediaType = getMediaType(genericQueryBuilder.getHeaders().getAcceptableMediaTypes()); + org.onap.aai.introspection.MarshallerProperties properties = + new org.onap.aai.introspection.MarshallerProperties.Builder( + org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build(); + + result = searchResults.marshal(properties); + response = Response.ok().entity(result).build(); + + LOGGER.debug(ver.size() + " node(s) traversed, " + queryResults.size() + " found"); + } + success = true; + } catch (AAIException e) { + success = false; + throw e; + } catch (Exception e) { + success = false; + throw new AAIException("AAI_5105", e); + } finally { + if (genericQueryBuilder.getDbEngine() != null) { + if (success) { + genericQueryBuilder.getDbEngine().commit(); + } else { + genericQueryBuilder.getDbEngine().rollback(); + } + } + + } + + return response; + } + + private URI craftUriFromQueryParams(Loader loader, String startNodeType, List<String> startNodeKeyParams) + throws UnsupportedEncodingException, IllegalArgumentException, UriBuilderException, AAIException { + Introspector relationship = loader.introspectorFromName("relationship"); + + relationship.setValue("related-to", startNodeType); + List<Object> relationshipDataList = relationship.getValue("relationship-data"); + + for (String keyData : startNodeKeyParams) { + int colonIndex = keyData.indexOf(":"); + if (colonIndex <= 0) { + throw new AAIException("AAI_6120", "Bad key param passed in: [" + keyData + "]"); + } else { + Introspector data = loader.introspectorFromName("relationship-data"); + data.setValue("relationship-key", keyData.substring(0, colonIndex)); + data.setValue("relationship-value", keyData.substring(colonIndex + 1)); + relationshipDataList.add(data.getUnderlyingObject()); + } + } + + RelationshipToURI parser = new RelationshipToURI(loader, relationship); + + return parser.getUri(); + } + + /** + * Run nodes query. + * + * @param nodesQuery + * @throws AAIException the AAI exception + */ + public Response runNodesQuery(NodesQueryBuilder nodesQuery) throws AAIException { + + Response response = null; + boolean success = true; String result = ""; - final String EQUALS = "EQUALS"; - final String DOES_NOT_EQUAL = "DOES-NOT-EQUAL"; - final String EXISTS = "EXISTS"; - final String DOES_NOT_EXIST = "DOES-NOT-EXIST"; - try { - - dbEngine.startTransaction(); - - Introspector target; - - if( targetNodeType == null || targetNodeType == "" ){ - throw new AAIException("AAI_6120", "null or empty target-node-type passed to the node query"); - } - - try { - target = loader.introspectorFromName(targetNodeType); - } catch (AAIUnknownObjectException e) { - throw new AAIException("AAI_6115", "Unrecognized nodeType [" + targetNodeType + "] passed to node query."); - } - - if( filterParams.isEmpty() && edgeFilterParams.isEmpty()){ - // For now, it's ok to pass no filter params. We'll just return ALL the nodes of the requested type. - LOGGER.warn("No filters passed to the node query"); - } - - StringBuilder queryStringForMsg = new StringBuilder(); - GraphTraversal<Vertex, Vertex> traversal = dbEngine.asAdmin().getReadOnlyTraversalSource().V().has(AAIProperties.NODE_TYPE, targetNodeType); - queryStringForMsg.append("has(\"aai-node-type\"," + targetNodeType + ")"); - - for( String filter : filterParams ) { - String [] pieces = filter.split(":"); - if( pieces.length < 2 ){ - throw new AAIException("AAI_6120", "bad filter passed to node query: [" + filter + "]"); - } - else { - String propName = this.findDbPropName(target, pieces[0]); - String filterType = pieces[1]; - if( filterType.equals(EQUALS)){ - if( pieces.length < 3 ){ - throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]"); - } - String value = "?"; - if( pieces.length == 3 ){ - value = pieces[2]; - } - else if( pieces.length > 3 ){ - // When a ipv6 address comes in as a value, it has colons in it which require us to - // pull the "value" off the end of the filter differently - int startPos4Value = propName.length() + filterType.length() + 3; - value = filter.substring(startPos4Value); - } - queryStringForMsg.append(".has(" + propName + "," + value + ")"); - traversal.has(propName,value); - } - else if( filterType.equals(DOES_NOT_EQUAL)){ - if( pieces.length < 3 ){ - throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]"); - } - String value = "?"; - if( pieces.length == 3 ){ - value = pieces[2]; - } - else if( pieces.length > 3 ){ - // When a ipv6 address comes in as a value, it has colons in it which require us to - // pull the "value" off the end of the filter differently - int startPos4Value = propName.length() + filterType.length() + 3; - value = filter.substring(startPos4Value); - } - queryStringForMsg.append(".hasNot(" + propName + "," + value + ")"); - traversal.not(__.has(propName,value)); - } - else if( filterType.equals(EXISTS)){ - queryStringForMsg.append(".has(" + propName + ")"); - traversal.has(propName); - } - else if( filterType.equals(DOES_NOT_EXIST)){ - queryStringForMsg.append(".hasNot(" + propName + ")"); - traversal.hasNot(propName); - } - else { - throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]"); - } - } - } - - if (!edgeFilterParams.isEmpty()) { - // edge-filter=pserver:EXISTS: OR pserver:EXISTS:hostname:XXX - // edge-filter=pserver:DOES-NOT-EXIST: OR pserver:DOES-NOT-EXIST:hostname:XXX - String filter = edgeFilterParams.get(0); // we process and allow only one edge filter for now - String [] pieces = filter.split(":"); - if( pieces.length < 2 || pieces.length == 3 || pieces.length > 4){ - throw new AAIException("AAI_6120", "bad edge-filter passed: [" + filter + "]"); - } else { - String nodeType = pieces[0].toLowerCase(); - String filterType = pieces[1].toUpperCase(); - Introspector otherNode; - if (!filterType.equals(EXISTS) && !filterType.equals(DOES_NOT_EXIST)) { - throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]"); - } - try { - otherNode = loader.introspectorFromName(nodeType); - } catch (AAIUnknownObjectException e) { - throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to node query."); - } - String propName = null; - String propValue = null; - if ( pieces.length >= 3) { - propName = this.findDbPropName(otherNode, pieces[2].toLowerCase()); - propValue = pieces[3]; - } - String[] edgeLabels = getEdgeLabel(targetNodeType, nodeType); - - GraphTraversal<Vertex, Vertex> edgeSearch = __.start(); - - edgeSearch.both(edgeLabels).has(AAIProperties.NODE_TYPE, nodeType); - if (propName != null) { - // check for matching property - if (propValue != null) { - edgeSearch.has(propName, propValue); - } else { - edgeSearch.has(propName); - } - } - - if( filterType.equals(DOES_NOT_EXIST)){ - traversal.where(__.not(edgeSearch)); - } else if (filterType.equals(EXISTS)) { - traversal.where(edgeSearch); - } - } - } - - List<Vertex> results = traversal.toList(); - Introspector searchResults = createSearchResults(loader, urlBuilder, results); - - String outputMediaType = getMediaType(headers.getAcceptableMediaTypes()); - org.onap.aai.introspection.MarshallerProperties properties = new org.onap.aai.introspection.MarshallerProperties.Builder( - org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build(); - - result = searchResults.marshal(properties); - response = Response.ok().entity(result).build(); - - success = true; - } catch (AAIException e) { - success = false; - throw e; - } catch (Exception e) { - success = false; - throw new AAIException("AAI_5105", e); - } finally { - if (dbEngine != null) { - if (success) { - dbEngine.commit(); - } else { - dbEngine.rollback(); - } - } - } - - return response; - } - - protected Introspector createSearchResults(Loader loader, UrlBuilder urlBuilder, List<Vertex> results) - throws AAIUnknownObjectException { - Introspector searchResults = loader.introspectorFromName("search-results"); - List<Object> resultDataList = searchResults.getValue("result-data"); - Stream<Vertex> stream; - if (results.size() >= 50) { - stream = results.parallelStream(); - } else { - stream = results.stream(); - } - boolean isParallel = stream.isParallel(); - stream.forEach(v -> { - String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); - - String thisNodeURL; - try { - thisNodeURL = urlBuilder.pathed(v); - Introspector resultData = loader.introspectorFromName("result-data"); - - resultData.setValue("resource-type", nodeType); - resultData.setValue("resource-link", thisNodeURL); - if (isParallel) { - synchronized (resultDataList) { - resultDataList.add(resultData.getUnderlyingObject()); - } - } else { - resultDataList.add(resultData.getUnderlyingObject()); - } - } catch (AAIException | AAIFormatVertexException e) { - throw new RuntimeException(e); - } - - }); - return searchResults; - } - - private String findDbPropName(Introspector obj, String propName) { - - Optional<String> result = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS); - if (result.isPresent()) { - return result.get(); - } else { - return propName; - } - } - - - /** - * Gets the edge label. - * - * @param targetNodeType the target node type - * @param nodeType the node type - * @return the edge label - * @throws AAIException the AAI exception - * @throws EdgeRuleNotFoundException - */ - public String[] getEdgeLabel(String targetNodeType, String nodeType) throws AAIException, EdgeRuleNotFoundException{ - - - EdgeRuleQuery query = new EdgeRuleQuery.Builder(targetNodeType, nodeType).build(); - Multimap<String, EdgeRule> edgeRules = ArrayListMultimap.create(); - edgeRules = edgeIngestor.getRules(query); - - //Map<String, EdgeRule> rules = EdgeRules.getInstance().getEdgeRules(targetNodeType, nodeType); - String[] results = edgeRules.values().stream().map(rule -> rule.getLabel()).collect(Collectors.toList()).toArray(new String[0]); - return results; - } - - - /** - * Run named query. - * - * @param fromAppId the from app id - * @param transId the trans id - * @param queryParameters the query parameters - * @param aaiExtMap the aai ext map - * @return the response - * @throws JAXBException the JAXB exception - * @throws AAIException the AAI exception - */ - public Response runNamedQuery(String fromAppId, String transId, String queryParameters, - DBConnectionType connectionType, - AAIExtensionMap aaiExtMap) throws JAXBException, AAIException { - - Introspector inventoryItems; - boolean success = true; - TransactionalGraphEngine dbEngine = null; - try { - - MoxyLoader loader = (MoxyLoader)loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); - DynamicJAXBContext jaxbContext = loader.getJAXBContext(); - dbEngine = new JanusGraphDBEngine( - QueryStyle.TRAVERSAL, - connectionType, - loader); - DBSerializer serializer = new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); - ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); - - dbEngine.startTransaction(); - org.onap.aai.restcore.MediaType mediaType = org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE; - String contentType = aaiExtMap.getHttpServletRequest().getContentType(); - if (contentType != null && contentType.contains("application/xml")) { - mediaType = org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE; - } - - if (queryParameters.length() == 0) { - queryParameters = "{}"; - } - - DynamicEntity modelAndNamedQuerySearch = (DynamicEntity)loader.unmarshal("ModelAndNamedQuerySearch", queryParameters, mediaType).getUnderlyingObject(); - if (modelAndNamedQuerySearch == null) { - throw new AAIException("AAI_5105"); - } - HashMap<String,Object> namedQueryLookupHash = new HashMap<String,Object>(); - - DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); - String namedQueryUuid = null; - if ((qp != null) && qp.isSet("namedQuery")) { - DynamicEntity namedQuery = (DynamicEntity) qp.get("namedQuery"); - - if (namedQuery.isSet("namedQueryUuid")) { - namedQueryUuid = namedQuery.get("namedQueryUuid"); - } - if (namedQuery.isSet("namedQueryName")) { - namedQueryLookupHash.put("named-query-name", namedQuery.get("namedQueryName")); - } - if (namedQuery.isSet("namedQueryVersion")) { - namedQueryLookupHash.put("named-query-version", namedQuery.get("namedQueryVersion")); - } - } - - if (namedQueryUuid == null) { - - DbMethHelper dbMethHelper = new DbMethHelper(loader, dbEngine); - List<Vertex> namedQueryVertices = dbMethHelper.locateUniqueVertices("named-query", namedQueryLookupHash); - for (Vertex vert : namedQueryVertices) { - namedQueryUuid = vert.<String>property("named-query-uuid").orElse(null); - // there should only be one, we'll pick the first if not - break; - } - } - - String secondaryFilterCutPoint = null; - - if (modelAndNamedQuerySearch.isSet("secondaryFilterCutPoint")) { - secondaryFilterCutPoint = modelAndNamedQuerySearch.get("secondaryFilterCutPoint"); - } - - List<Map<String,Object>> startNodeFilterHash = new ArrayList<>(); - - mapInstanceFilters((DynamicEntity)modelAndNamedQuerySearch.get("instanceFilters"), - startNodeFilterHash, jaxbContext); - - Map<String,Object> secondaryFilterHash = new HashMap<>(); - - mapSecondaryFilters((DynamicEntity)modelAndNamedQuerySearch.get("secondaryFilts"), - secondaryFilterHash, jaxbContext); - - List<ResultSet> resultSet = processor.queryByNamedQuery(transId, fromAppId, - namedQueryUuid, startNodeFilterHash, aaiExtMap.getApiVersion(), secondaryFilterCutPoint, secondaryFilterHash); - - inventoryItems = loader.introspectorFromName("inventory-response-items"); - - List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); - - inventoryItems.setValue("inventory-response-item", invItemList); - success = true; - } catch (AAIException e) { - success = false; - throw e; - } catch (Exception e) { - success = false; - throw new AAIException("AAI_5105", e); - } finally { - if (dbEngine != null) { - if (success) { - dbEngine.commit(); - } else { - dbEngine.rollback(); - } - } - } - - return getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders()); - } - - /** - * Execute model operation. - * - * @param fromAppId the from app id - * @param transId the trans id - * @param queryParameters the query parameters - * @param isDelete the is delete - * @param aaiExtMap the aai ext map - * @return the response - * @throws JAXBException the JAXB exception - * @throws AAIException the AAI exception - * @throws DynamicException the dynamic exception - * @throws UnsupportedEncodingException the unsupported encoding exception - */ - public Response executeModelOperation(String fromAppId, String transId, String queryParameters, - DBConnectionType connectionType, - boolean isDelete, - AAIExtensionMap aaiExtMap) throws JAXBException, AAIException, DynamicException, UnsupportedEncodingException { - Response response; - boolean success = true; - TransactionalGraphEngine dbEngine = null; - try { - - MoxyLoader loader = (MoxyLoader) loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); - DynamicJAXBContext jaxbContext = loader.getJAXBContext(); - dbEngine = new JanusGraphDBEngine( - QueryStyle.TRAVERSAL, - connectionType, - loader); - DBSerializer serializer = new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); - ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); - dbEngine.startTransaction(); - - - org.onap.aai.restcore.MediaType mediaType = org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE; - String contentType = aaiExtMap.getHttpServletRequest().getContentType(); - if (contentType != null && contentType.contains("application/xml")) { - mediaType = org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE; - } - - if (queryParameters.length() == 0) { - queryParameters = "{}"; - } - - DynamicEntity modelAndNamedQuerySearch = (DynamicEntity)loader.unmarshal("ModelAndNamedQuerySearch", queryParameters, mediaType).getUnderlyingObject(); - if (modelAndNamedQuerySearch == null) { - throw new AAIException("AAI_5105"); - } - - Map<String,Object> modelQueryLookupHash = new HashMap<>(); - - String modelVersionId = null; - String modelName = null; - String modelInvariantId = null; - String modelVersion = null; - String topNodeType = null; - - if (modelAndNamedQuerySearch.isSet("topNodeType")) { - topNodeType = modelAndNamedQuerySearch.get("topNodeType"); - } - - // the ways to get a model: - - // 1. model-version-id (previously model-name-version-id - // 2. model-invariant-id (previously model-id) + model-version - // 3. model-name + model-version - - // we will support both using the OverloadedModel object in the v9 oxm. This allows us to unmarshal - // either an old-style model or new-style model + model-ver object - if (modelAndNamedQuerySearch.isSet("queryParameters")) { - DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); - - if (qp.isSet("model")) { - DynamicEntity model = (DynamicEntity) qp.get("model"); - - // on an old-style model object, the following 4 attrs were all present - if (model.isSet("modelNameVersionId")) { - modelVersionId = model.get("modelNameVersionId"); - } - if (model.isSet("modelId")) { - modelInvariantId = model.get("modelId"); - } - if (model.isSet("modelName")) { - modelName = model.get("modelName"); - } - if (model.isSet("modelVersion")) { - modelVersion = model.get("modelVersion"); - } - - // new style splits model-invariant-id from the other 3 attrs. This is - // the only way to directly look up the model object - if (model.isSet("modelInvariantId")) { - modelInvariantId = model.get("modelInvariantId"); - } - - if (model.isSet("modelVers")) { - // we know that this is new style, because modelVers was not an option - // before v9 - DynamicEntity modelVers = (DynamicEntity) model.get("modelVers"); - if (modelVers.isSet("modelVer")) { - List<DynamicEntity> modelVerList = modelVers.get("modelVer"); - // if they send more than one, too bad, they get the first one - DynamicEntity modelVer = modelVerList.get(0); - if (modelVer.isSet("modelName")) { - modelName = modelVer.get("modelName"); - } - if (modelVer.isSet("modelVersionId")) { - modelVersionId = modelVer.get("modelVersionId"); - } - if (modelVer.isSet("modelVersion")) { - modelVersion = modelVer.get("modelVersion"); - } - } - } - } - } - - List<Map<String,Object>> startNodeFilterHash = new ArrayList<>(); - - String resourceVersion = mapInstanceFilters((DynamicEntity)modelAndNamedQuerySearch.get("instanceFilters"), - startNodeFilterHash, jaxbContext); - - if (isDelete) { - - List<ResultSet> resultSet = processor.queryByModel(transId, fromAppId, - modelVersionId, modelInvariantId, modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion() ); - - Map<Object,String> objectToVertMap = new HashMap<>(); - List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); - - ResultSet rs = resultSet.get(0); - - Vertex firstVert = rs.getVert(); - String restURI = serializer.getURIForVertex(firstVert).toString(); - String notificationVersion = schemaVersions.getDefaultVersion().toString(); - Map<String,String> delResult = processor.runDeleteByModel( transId, fromAppId, - modelVersionId, topNodeType, startNodeFilterHash.get(0), aaiExtMap.getApiVersion(), resourceVersion ); - - String resultStr = ""; - for (Map.Entry<String,String> ent : delResult.entrySet()) { - resultStr += "v[" + ent.getKey() + "] " + ent.getValue() + ",\n"; - } - resultStr.trim(); - - // Note - notifications are now done down in the individual "remove" calls done in runDeleteByModel() above. - - response = Response.ok(resultStr).build(); - - } else { - List<ResultSet> resultSet = processor.queryByModel( transId, fromAppId, - modelVersionId, modelInvariantId, modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion() ); - - Introspector inventoryItems = loader.introspectorFromName("inventory-response-items"); - - List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); - - inventoryItems.setValue("inventory-response-item", invItemList); - - response = getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders()); - } - success = true; - } catch (AAIException e) { - success = false; - throw e; - } catch (Exception e) { - success = false; - throw new AAIException("AAI_5105", e); - } finally { - if (dbEngine != null) { - if (success) { - dbEngine.commit(); - } else { - dbEngine.rollback(); - } - } - } - - return response; - } - - private Response getResponseFromIntrospector(Introspector obj, HttpHeaders headers) { - boolean isJson = false; - for (MediaType mt : headers.getAcceptableMediaTypes()) { - if (MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) { - isJson = true; - break; - } - } - org.onap.aai.introspection.MarshallerProperties properties; - if (isJson) { - properties = - new org.onap.aai.introspection.MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE).build(); - } else { - properties = - new org.onap.aai.introspection.MarshallerProperties.Builder(org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE).build(); - } - - String marshalledObj = obj.marshal(properties); - return Response.ok().entity(marshalledObj).build(); - } - - /** - * Map instance filters. - * - * @param instanceFilters the instance filters - * @param startNodeFilterHash the start node filter hash - * @param jaxbContext the jaxb context - * @return the string - */ - private String mapInstanceFilters(DynamicEntity instanceFilters, List<Map<String,Object>> startNodeFilterHash, DynamicJAXBContext jaxbContext) { - - if (instanceFilters == null || !instanceFilters.isSet("instanceFilter")) { - return null; - } - @SuppressWarnings("unchecked") - List<DynamicEntity> instanceFilter = (ArrayList<DynamicEntity>)instanceFilters.get("instanceFilter"); - String resourceVersion = null; - - for (DynamicEntity instFilt : instanceFilter) { - List<DynamicEntity> any = instFilt.get("any"); - HashMap<String,Object> thisNodeFilterHash = new HashMap<String,Object>(); - for (DynamicEntity anyEnt : any) { - String clazz = anyEnt.getClass().getCanonicalName(); - String simpleClazz = anyEnt.getClass().getSimpleName(); - - String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz); - - DynamicType anyEntType = jaxbContext.getDynamicType(clazz); - - for (String propName : anyEntType.getPropertiesNames()) { - // hyphencase the prop and throw it on the hash - if (anyEnt.isSet(propName)) { - thisNodeFilterHash.put(nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), anyEnt.get(propName)); - if (propName.equals("resourceVersion") && resourceVersion == null) { - resourceVersion = (String)anyEnt.get(propName); - } - } - } - } - startNodeFilterHash.add(thisNodeFilterHash); - } - return resourceVersion; - } - - /** - * Map secondary filters. - * - * @param secondaryFilts the secondary filters - * @param secondaryFilterHash the secondary filter hash - * @param jaxbContext the jaxb context - * @return the string - */ - private void mapSecondaryFilters(DynamicEntity secondaryFilts, Map<String,Object> secondaryFilterHash, DynamicJAXBContext jaxbContext) { - - if (secondaryFilts == null || !secondaryFilts.isSet("secondaryFilt")) { - return; - } - @SuppressWarnings("unchecked") - List<DynamicEntity> secondaryFilter = (ArrayList<DynamicEntity>)secondaryFilts.get("secondaryFilt"); - - for (DynamicEntity secondaryFilt : secondaryFilter) { - List<DynamicEntity> any = secondaryFilt.get("any"); - - for (DynamicEntity anyEnt : any) { - String clazz = anyEnt.getClass().getCanonicalName(); - String simpleClazz = anyEnt.getClass().getSimpleName(); - - String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz); - - DynamicType anyEntType = jaxbContext.getDynamicType(clazz); - - for (String propName : anyEntType.getPropertiesNames()) { - // hyphencase the prop and throw it on the hash - if (anyEnt.isSet(propName)) { - secondaryFilterHash.put(nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), anyEnt.get(propName)); - } - } - } - } - } - - /** - * Remap inventory items. - * - * @param invResultItem the inv result item - * @param jaxbContext the jaxb context - * @param includeTheseVertices the include these vertices - * @param objectToVertMap the object to vert map - * @param aaiExtMap the aai ext map - * @return the dynamic entity - */ - private DynamicEntity remapInventoryItems(DynamicEntity invResultItem, DynamicJAXBContext jaxbContext, - Map<String,String> includeTheseVertices, Map<Object,String> objectToVertMap, AAIExtensionMap aaiExtMap) { - - - DynamicEntity inventoryItem = jaxbContext.newDynamicEntity("inventory.aai.onap.org." + aaiExtMap.getApiVersion() + ".InventoryResponseItem"); - Object item = invResultItem.get("item"); - inventoryItem.set("modelName", invResultItem.get("modelName")); - inventoryItem.set("item", item); - inventoryItem.set("extraProperties", invResultItem.get("extraProperties")); - - String vertexId = ""; - - if (objectToVertMap.containsKey(item)) { - vertexId = objectToVertMap.get(item); - } - - if (includeTheseVertices.containsKey(vertexId)) { - if (invResultItem.isSet("inventoryResponseItems")) { - List<DynamicEntity> invItemList = new ArrayList<DynamicEntity>(); - DynamicEntity inventoryItems = jaxbContext.newDynamicEntity("inventory.aai.att.com." + aaiExtMap.getApiVersion() + ".InventoryResponseItems"); - DynamicEntity subInventoryResponseItems = invResultItem.get("inventoryResponseItems"); - List<DynamicEntity> subInventoryResponseItemList = subInventoryResponseItems.get("inventoryResponseItem"); - for (DynamicEntity ent : subInventoryResponseItemList) { - DynamicEntity invItem = remapInventoryItems(ent, jaxbContext, includeTheseVertices, objectToVertMap, aaiExtMap); - if (invItem != null) { - invItemList.add(invItem); - } - } - inventoryItems.set("inventoryResponseItem", invItemList); - inventoryItem.set("inventoryResponseItems", inventoryItems); - } - } - return inventoryItem; - } - - /** - * Unpack result set. - * - * @param g the g - * @param resultSetList the result set list - * @param jaxbContext the jaxb context - * @param aaiResources the aai resources - * @param objectToVertMap the object to vert map - * @param aaiExtMap the aai ext map - * @return the array list - * @throws AAIException the AAI exception - */ - // this should return an inventoryItem - private List<Object> unpackResultSet(List<ResultSet> resultSetList, - TransactionalGraphEngine engine, - Loader loader, - DBSerializer serializer) throws AAIException { - - List<Object> resultList = new ArrayList<>(); - - for (ResultSet resultSet : resultSetList) { - - if( resultSet.getVert() == null ){ - continue; - } - - Introspector inventoryItem = loader.introspectorFromName("inventory-response-item"); - Introspector inventoryItems = loader.introspectorFromName("inventory-response-items"); - // add this inventoryItem to the resultList for this level - resultList.add(inventoryItem.getUnderlyingObject()); - - Vertex vert = resultSet.getVert(); - - String aaiNodeType = vert.<String>property("aai-node-type").orElse(null); - - if (aaiNodeType != null) { - Introspector thisObj = loader.introspectorFromName(aaiNodeType); - - if (resultSet.getExtraPropertyHash() != null) { - Map<String,Object> extraProperties = resultSet.getExtraPropertyHash(); - - Introspector extraPropertiesEntity = loader.introspectorFromName("extra-properties"); - - List<Object> extraPropsList = extraPropertiesEntity.getValue("extra-property"); - - for (Map.Entry<String,Object> ent : extraProperties.entrySet()) { - String propName = ent.getKey(); - Object propVal = ent.getValue(); - - Introspector extraPropEntity = loader.introspectorFromName("extra-property"); - - extraPropEntity.setValue("property-name", propName); - extraPropEntity.setValue("property-value", propVal); - - extraPropsList.add(extraPropEntity.getUnderlyingObject()); - - } - inventoryItem.setValue("extra-properties", extraPropertiesEntity.getUnderlyingObject()); - } - - try { - serializer.dbToObject(Collections.singletonList(vert), thisObj, 0, true, "false"); - } catch (UnsupportedEncodingException e1) { - throw new AAIException("AAI_5105"); - } - PropertyLimitDesc propertyLimitDesc = resultSet.getPropertyLimitDesc(); - - if (propertyLimitDesc != null) { - - if (PropertyLimitDesc.SHOW_NONE.equals(propertyLimitDesc)) { - HashMap<String,Object> emptyPropertyOverRideHash = new HashMap<String,Object>(); - for (String key : thisObj.getAllKeys()) { - emptyPropertyOverRideHash.put(key, null); - } - filterProperties(thisObj, emptyPropertyOverRideHash); - } else if (PropertyLimitDesc.SHOW_ALL.equals(propertyLimitDesc)) { - //keep everything - } else if (PropertyLimitDesc.SHOW_NAME_AND_KEYS_ONLY.equals(propertyLimitDesc)) { - HashMap<String,Object> keysAndNamesPropHash = new HashMap<String,Object>(); - - for (String key : thisObj.getAllKeys()) { - keysAndNamesPropHash.put(key, null); - } - String namePropMetaData = thisObj.getMetadata(ObjectMetadata.NAME_PROPS); - if (namePropMetaData != null) { - String[] nameProps = namePropMetaData.split(","); - for (String names : nameProps) { - keysAndNamesPropHash.put(names, null); - } - } - filterProperties(thisObj, keysAndNamesPropHash); - } - } else { - if (resultSet.getPropertyOverRideHash() != null && resultSet.getPropertyOverRideHash().size() > 0) { - Map<String,Object> propertyOverRideHash = resultSet.getPropertyOverRideHash(); - if (propertyOverRideHash.containsKey("persona-model-id")) { - propertyOverRideHash.remove("persona-model-id"); - propertyOverRideHash.put("model-invariant-id", null); - } - for (String key : thisObj.getAllKeys()) { - propertyOverRideHash.put(key, null); - } - filterProperties(thisObj, propertyOverRideHash); - } else { - //keep everything - } - } - - if (thisObj != null) { - inventoryItem.setValue("item", thisObj.getUnderlyingObject()); - - String modelName = null; - try { - // Try to get the modelName if we can. Otherwise, do not fail, just return what we have already. - String modelInvariantIdLocal = (String)vert.<String>property("model-invariant-id-local").orElse(null); // this one points at a model - String modelVersionIdLocal = (String)vert.<String>property("model-version-id-local").orElse(null); // this one points at a model-ver - - if ( (modelInvariantIdLocal != null && modelVersionIdLocal != null) - && (modelInvariantIdLocal.length() > 0 && modelVersionIdLocal.length() > 0) ) { - Introspector modelVer = loader.introspectorFromName("model-ver"); - modelVer.setValue("model-version-id", modelVersionIdLocal); - QueryBuilder builder = engine.getQueryBuilder().createDBQuery(modelVer); - List<Vertex> modelVerVerts = builder.toList(); - if( (modelVerVerts != null) && (modelVerVerts.size() == 1) ) { - Vertex modelVerVert = modelVerVerts.get(0); - modelName = modelVerVert.<String>property("model-name").orElse(null); - if (modelName != null && modelName.length() > 0) { - inventoryItem.setValue("model-name", modelName); - } - } - } - } catch (DynamicException e) { - ; // it's ok, dynamic object might not have these fields - } catch (Exception e) { - ; // it's ok, couldn't find a matching model - } - - if (resultSet.getSubResultSet() != null) { - List<ResultSet> subResultSet = resultSet.getSubResultSet(); - if (subResultSet != null && subResultSet.size() > 0 ) { - List<Object> res = unpackResultSet(subResultSet, engine, loader, serializer); - if (res.size() > 0) { - inventoryItems.setValue("inventory-response-item", res); - inventoryItem.setValue("inventory-response-items", inventoryItems.getUnderlyingObject()); - } - } - } - } - } - } - - return resultList; - } - - private void filterProperties(Introspector thisObj, Map<String, Object> override) { - - thisObj.getProperties().stream().filter(x -> { - return !override.containsKey(x); - }).forEach(prop -> { - if (thisObj.isSimpleType(prop)) { - thisObj.setValue(prop, null); - } - }); - - } - - /** - * Gets the media type. - * - * @param mediaTypeList the media type list - * @return the media type - */ - protected String getMediaType(List <MediaType> mediaTypeList) { - String mediaType = MediaType.APPLICATION_JSON; // json is the default - for (MediaType mt : mediaTypeList) { - if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) { - mediaType = MediaType.APPLICATION_XML; - } - } - return mediaType; - } + final String EQUALS = "EQUALS"; + final String DOES_NOT_EQUAL = "DOES-NOT-EQUAL"; + final String EXISTS = "EXISTS"; + final String DOES_NOT_EXIST = "DOES-NOT-EXIST"; + try { + + nodesQuery.getDbEngine().startTransaction(); + + Introspector target; + + if (StringUtils.isBlank(nodesQuery.getTargetNodeType()) + || StringUtils.isBlank(nodesQuery.getTargetNodeType())) { + throw new AAIException("AAI_6120", "null or empty target-node-type passed to the node query"); + } + + try { + target = nodesQuery.getLoader().introspectorFromName(nodesQuery.getTargetNodeType()); + } catch (AAIUnknownObjectException e) { + throw new AAIException("AAI_6115", + "Unrecognized nodeType [" + nodesQuery.getTargetNodeType() + "] passed to node query."); + } + + if (nodesQuery.getFilterParams().isEmpty() && nodesQuery.getEdgeFilterParams().isEmpty()) { + // For now, it's ok to pass no filter params. We'll just return ALL the nodes of the requested type. + LOGGER.warn("No filters passed to the node query"); + } + + StringBuilder queryStringForMsg = new StringBuilder(); + GraphTraversal<Vertex, Vertex> traversal = nodesQuery.getDbEngine().asAdmin().getReadOnlyTraversalSource() + .V().has(AAIProperties.NODE_TYPE, nodesQuery.getTargetNodeType()); + queryStringForMsg.append("has(\"aai-node-type\"," + nodesQuery.getTargetNodeType() + ")"); + + for (String filter : nodesQuery.getFilterParams()) { + String[] pieces = filter.split(":"); + if (pieces.length < 2) { + throw new AAIException("AAI_6120", "bad filter passed to node query: [" + filter + "]"); + } else { + String propName = this.findDbPropName(target, pieces[0]); + String filterType = pieces[1]; + if (filterType.equals(EQUALS)) { + if (pieces.length < 3) { + throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]"); + } + String value = "?"; + if (pieces.length == 3) { + value = pieces[2]; + } else if (pieces.length > 3) { + // When a ipv6 address comes in as a value, it has colons in it which require us to + // pull the "value" off the end of the filter differently + int startPos4Value = propName.length() + filterType.length() + 3; + value = filter.substring(startPos4Value); + } + queryStringForMsg.append(".has(" + propName + "," + value + ")"); + traversal.has(propName, value); + } else if (filterType.equals(DOES_NOT_EQUAL)) { + if (pieces.length < 3) { + throw new AAIException("AAI_6120", "No value passed for filter: [" + filter + "]"); + } + String value = "?"; + if (pieces.length == 3) { + value = pieces[2]; + } else if (pieces.length > 3) { + // When a ipv6 address comes in as a value, it has colons in it which require us to + // pull the "value" off the end of the filter differently + int startPos4Value = propName.length() + filterType.length() + 3; + value = filter.substring(startPos4Value); + } + queryStringForMsg.append(".hasNot(" + propName + "," + value + ")"); + traversal.not(__.has(propName, value)); + } else if (filterType.equals(EXISTS)) { + queryStringForMsg.append(".has(" + propName + ")"); + traversal.has(propName); + } else if (filterType.equals(DOES_NOT_EXIST)) { + queryStringForMsg.append(".hasNot(" + propName + ")"); + traversal.hasNot(propName); + } else { + throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]"); + } + } + } + + if (!nodesQuery.getEdgeFilterParams().isEmpty()) { + // edge-filter=pserver:EXISTS: OR pserver:EXISTS:hostname:XXX + // edge-filter=pserver:DOES-NOT-EXIST: OR pserver:DOES-NOT-EXIST:hostname:XXX + String filter = nodesQuery.getEdgeFilterParams().get(0); // we process and allow only one edge filter + // for now + String[] pieces = filter.split(":"); + if (pieces.length < 2 || pieces.length == 3 || pieces.length > 4) { + throw new AAIException("AAI_6120", "bad edge-filter passed: [" + filter + "]"); + } else { + String nodeType = pieces[0].toLowerCase(); + String filterType = pieces[1].toUpperCase(); + Introspector otherNode; + if (!filterType.equals(EXISTS) && !filterType.equals(DOES_NOT_EXIST)) { + throw new AAIException("AAI_6120", "bad filterType passed: [" + filterType + "]"); + } + try { + otherNode = nodesQuery.getLoader().introspectorFromName(nodeType); + } catch (AAIUnknownObjectException e) { + throw new AAIException("AAI_6115", + "Unrecognized nodeType [" + nodeType + "] passed to node query."); + } + String propName = null; + String propValue = null; + if (pieces.length >= 3) { + propName = this.findDbPropName(otherNode, pieces[2].toLowerCase()); + propValue = pieces[3]; + } + String[] edgeLabels = getEdgeLabel(nodesQuery.getTargetNodeType(), nodeType); + + GraphTraversal<Vertex, Vertex> edgeSearch = __.start(); + + edgeSearch.both(edgeLabels).has(AAIProperties.NODE_TYPE, nodeType); + if (propName != null) { + // check for matching property + if (propValue != null) { + edgeSearch.has(propName, propValue); + } else { + edgeSearch.has(propName); + } + } + + if (filterType.equals(DOES_NOT_EXIST)) { + traversal.where(__.not(edgeSearch)); + } else if (filterType.equals(EXISTS)) { + traversal.where(edgeSearch); + } + } + } + + List<Vertex> results = traversal.toList(); + Introspector searchResults = + createSearchResults(nodesQuery.getLoader(), nodesQuery.getUrlBuilder(), results); + + String outputMediaType = getMediaType(nodesQuery.getHeaders().getAcceptableMediaTypes()); + org.onap.aai.introspection.MarshallerProperties properties = + new org.onap.aai.introspection.MarshallerProperties.Builder( + org.onap.aai.restcore.MediaType.getEnum(outputMediaType)).build(); + + result = searchResults.marshal(properties); + response = Response.ok().entity(result).build(); + + success = true; + } catch (AAIException e) { + success = false; + throw e; + } catch (Exception e) { + success = false; + throw new AAIException("AAI_5105", e); + } finally { + if (nodesQuery.getDbEngine() != null) { + if (success) { + nodesQuery.getDbEngine().commit(); + } else { + nodesQuery.getDbEngine().rollback(); + } + } + } + + return response; + } + + protected Introspector createSearchResults(Loader loader, UrlBuilder urlBuilder, List<Vertex> results) + throws AAIUnknownObjectException { + Introspector searchResults = loader.introspectorFromName("search-results"); + List<Object> resultDataList = searchResults.getValue("result-data"); + Stream<Vertex> stream; + if (results.size() >= 50) { + stream = results.parallelStream(); + } else { + stream = results.stream(); + } + boolean isParallel = stream.isParallel(); + stream.forEach(v -> { + String nodeType = v.<String>property(AAIProperties.NODE_TYPE).orElse(null); + + String thisNodeURL; + try { + thisNodeURL = urlBuilder.pathed(v); + Introspector resultData = loader.introspectorFromName("result-data"); + + resultData.setValue("resource-type", nodeType); + resultData.setValue("resource-link", thisNodeURL); + if (isParallel) { + synchronized (resultDataList) { + resultDataList.add(resultData.getUnderlyingObject()); + } + } else { + resultDataList.add(resultData.getUnderlyingObject()); + } + } catch (AAIException | AAIFormatVertexException e) { + throw new RuntimeException(e); + } + + }); + return searchResults; + } + + private String findDbPropName(Introspector obj, String propName) { + + Optional<String> result = obj.getPropertyMetadata(propName, PropertyMetadata.DB_ALIAS); + if (result.isPresent()) { + return result.get(); + } else { + return propName; + } + } + + + /** + * Gets the edge label. + * + * @param targetNodeType the target node type + * @param nodeType the node type + * @return the edge label + * @throws AAIException the AAI exception + * @throws EdgeRuleNotFoundException + */ + public String[] getEdgeLabel(String targetNodeType, String nodeType) + throws AAIException, EdgeRuleNotFoundException { + + + EdgeRuleQuery query = new EdgeRuleQuery.Builder(targetNodeType, nodeType).build(); + Multimap<String, EdgeRule> edgeRules = ArrayListMultimap.create(); + edgeRules = edgeIngestor.getRules(query); + + // Map<String, EdgeRule> rules = EdgeRules.getInstance().getEdgeRules(targetNodeType, nodeType); + String[] results = edgeRules.values().stream().map(rule -> rule.getLabel()).collect(Collectors.toList()) + .toArray(new String[0]); + return results; + } + + + /** + * Run named query. + * + * @param fromAppId the from app id + * @param transId the trans id + * @param queryParameters the query parameters + * @param aaiExtMap the aai ext map + * @return the response + * @throws JAXBException the JAXB exception + * @throws AAIException the AAI exception + */ + public Response runNamedQuery(String fromAppId, String transId, String queryParameters, + DBConnectionType connectionType, AAIExtensionMap aaiExtMap) throws JAXBException, AAIException { + + Introspector inventoryItems; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + try { + + MoxyLoader loader = (MoxyLoader) loaderFactory.createLoaderForVersion(ModelType.MOXY, + schemaVersions.getDefaultVersion()); + DynamicJAXBContext jaxbContext = loader.getJAXBContext(); + dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, connectionType, loader); + DBSerializer serializer = + new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); + ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); + + dbEngine.startTransaction(); + org.onap.aai.restcore.MediaType mediaType = org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE; + String contentType = aaiExtMap.getHttpServletRequest().getContentType(); + if (contentType != null && contentType.contains("application/xml")) { + mediaType = org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE; + } + + if (queryParameters.length() == 0) { + queryParameters = "{}"; + } + + DynamicEntity modelAndNamedQuerySearch = (DynamicEntity) loader + .unmarshal("ModelAndNamedQuerySearch", queryParameters, mediaType).getUnderlyingObject(); + if (modelAndNamedQuerySearch == null) { + throw new AAIException("AAI_5105"); + } + HashMap<String, Object> namedQueryLookupHash = new HashMap<String, Object>(); + + DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); + String namedQueryUuid = null; + if ((qp != null) && qp.isSet("namedQuery")) { + DynamicEntity namedQuery = (DynamicEntity) qp.get("namedQuery"); + + if (namedQuery.isSet("namedQueryUuid")) { + namedQueryUuid = namedQuery.get("namedQueryUuid"); + } + if (namedQuery.isSet("namedQueryName")) { + namedQueryLookupHash.put("named-query-name", namedQuery.get("namedQueryName")); + } + if (namedQuery.isSet("namedQueryVersion")) { + namedQueryLookupHash.put("named-query-version", namedQuery.get("namedQueryVersion")); + } + } + + if (namedQueryUuid == null) { + + DbMethHelper dbMethHelper = new DbMethHelper(loader, dbEngine); + List<Vertex> namedQueryVertices = + dbMethHelper.locateUniqueVertices("named-query", namedQueryLookupHash); + for (Vertex vert : namedQueryVertices) { + namedQueryUuid = vert.<String>property("named-query-uuid").orElse(null); + // there should only be one, we'll pick the first if not + break; + } + } + + String secondaryFilterCutPoint = null; + + if (modelAndNamedQuerySearch.isSet("secondaryFilterCutPoint")) { + secondaryFilterCutPoint = modelAndNamedQuerySearch.get("secondaryFilterCutPoint"); + } + + List<Map<String, Object>> startNodeFilterHash = new ArrayList<>(); + + mapInstanceFilters((DynamicEntity) modelAndNamedQuerySearch.get("instanceFilters"), startNodeFilterHash, + jaxbContext); + + Map<String, Object> secondaryFilterHash = new HashMap<>(); + + mapSecondaryFilters((DynamicEntity) modelAndNamedQuerySearch.get("secondaryFilts"), secondaryFilterHash, + jaxbContext); + + List<ResultSet> resultSet = processor.queryByNamedQuery(transId, fromAppId, namedQueryUuid, + startNodeFilterHash, aaiExtMap.getApiVersion(), secondaryFilterCutPoint, secondaryFilterHash); + + inventoryItems = loader.introspectorFromName("inventory-response-items"); + + List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); + + inventoryItems.setValue("inventory-response-item", invItemList); + success = true; + } catch (AAIException e) { + success = false; + throw e; + } catch (Exception e) { + success = false; + throw new AAIException("AAI_5105", e); + } finally { + if (dbEngine != null) { + if (success) { + dbEngine.commit(); + } else { + dbEngine.rollback(); + } + } + } + + return getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders()); + } + + /** + * Execute model operation. + * + * @param fromAppId the from app id + * @param transId the trans id + * @param queryParameters the query parameters + * @param isDelete the is delete + * @param aaiExtMap the aai ext map + * @return the response + * @throws JAXBException the JAXB exception + * @throws AAIException the AAI exception + * @throws DynamicException the dynamic exception + * @throws UnsupportedEncodingException the unsupported encoding exception + */ + public Response executeModelOperation(String fromAppId, String transId, String queryParameters, + DBConnectionType connectionType, boolean isDelete, AAIExtensionMap aaiExtMap) + throws JAXBException, AAIException, DynamicException, UnsupportedEncodingException { + Response response; + boolean success = true; + TransactionalGraphEngine dbEngine = null; + try { + + MoxyLoader loader = (MoxyLoader) loaderFactory.createLoaderForVersion(ModelType.MOXY, + schemaVersions.getDefaultVersion()); + DynamicJAXBContext jaxbContext = loader.getJAXBContext(); + dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, connectionType, loader); + DBSerializer serializer = + new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); + ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); + dbEngine.startTransaction(); + + + org.onap.aai.restcore.MediaType mediaType = org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE; + String contentType = aaiExtMap.getHttpServletRequest().getContentType(); + if (contentType != null && contentType.contains("application/xml")) { + mediaType = org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE; + } + + if (queryParameters.length() == 0) { + queryParameters = "{}"; + } + + DynamicEntity modelAndNamedQuerySearch = (DynamicEntity) loader + .unmarshal("ModelAndNamedQuerySearch", queryParameters, mediaType).getUnderlyingObject(); + if (modelAndNamedQuerySearch == null) { + throw new AAIException("AAI_5105"); + } + + Map<String, Object> modelQueryLookupHash = new HashMap<>(); + + String modelVersionId = null; + String modelName = null; + String modelInvariantId = null; + String modelVersion = null; + String topNodeType = null; + + if (modelAndNamedQuerySearch.isSet("topNodeType")) { + topNodeType = modelAndNamedQuerySearch.get("topNodeType"); + } + + // the ways to get a model: + + // 1. model-version-id (previously model-name-version-id + // 2. model-invariant-id (previously model-id) + model-version + // 3. model-name + model-version + + // we will support both using the OverloadedModel object in the v9 oxm. This allows us to unmarshal + // either an old-style model or new-style model + model-ver object + if (modelAndNamedQuerySearch.isSet("queryParameters")) { + DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); + + if (qp.isSet("model")) { + DynamicEntity model = (DynamicEntity) qp.get("model"); + + // on an old-style model object, the following 4 attrs were all present + if (model.isSet("modelNameVersionId")) { + modelVersionId = model.get("modelNameVersionId"); + } + if (model.isSet("modelId")) { + modelInvariantId = model.get("modelId"); + } + if (model.isSet("modelName")) { + modelName = model.get("modelName"); + } + if (model.isSet("modelVersion")) { + modelVersion = model.get("modelVersion"); + } + + // new style splits model-invariant-id from the other 3 attrs. This is + // the only way to directly look up the model object + if (model.isSet("modelInvariantId")) { + modelInvariantId = model.get("modelInvariantId"); + } + + if (model.isSet("modelVers")) { + // we know that this is new style, because modelVers was not an option + // before v9 + DynamicEntity modelVers = (DynamicEntity) model.get("modelVers"); + if (modelVers.isSet("modelVer")) { + List<DynamicEntity> modelVerList = modelVers.get("modelVer"); + // if they send more than one, too bad, they get the first one + DynamicEntity modelVer = modelVerList.get(0); + if (modelVer.isSet("modelName")) { + modelName = modelVer.get("modelName"); + } + if (modelVer.isSet("modelVersionId")) { + modelVersionId = modelVer.get("modelVersionId"); + } + if (modelVer.isSet("modelVersion")) { + modelVersion = modelVer.get("modelVersion"); + } + } + } + } + } + + List<Map<String, Object>> startNodeFilterHash = new ArrayList<>(); + + String resourceVersion = mapInstanceFilters((DynamicEntity) modelAndNamedQuerySearch.get("instanceFilters"), + startNodeFilterHash, jaxbContext); + + if (isDelete) { + + List<ResultSet> resultSet = processor.queryByModel(transId, fromAppId, modelVersionId, modelInvariantId, + modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion()); + + Map<Object, String> objectToVertMap = new HashMap<>(); + List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); + + ResultSet rs = resultSet.get(0); + + Vertex firstVert = rs.getVert(); + String restURI = serializer.getURIForVertex(firstVert).toString(); + String notificationVersion = schemaVersions.getDefaultVersion().toString(); + Map<String, String> delResult = processor.runDeleteByModel(transId, fromAppId, modelVersionId, + topNodeType, startNodeFilterHash.get(0), aaiExtMap.getApiVersion(), resourceVersion); + + String resultStr = ""; + for (Map.Entry<String, String> ent : delResult.entrySet()) { + resultStr += "v[" + ent.getKey() + "] " + ent.getValue() + ",\n"; + } + resultStr.trim(); + + // Note - notifications are now done down in the individual "remove" calls done in + // runDeleteByModel() above. + + response = Response.ok(resultStr).build(); + + } else { + List<ResultSet> resultSet = processor.queryByModel(transId, fromAppId, modelVersionId, modelInvariantId, + modelName, topNodeType, startNodeFilterHash, aaiExtMap.getApiVersion()); + + Introspector inventoryItems = loader.introspectorFromName("inventory-response-items"); + + List<Object> invItemList = unpackResultSet(resultSet, dbEngine, loader, serializer); + + inventoryItems.setValue("inventory-response-item", invItemList); + + response = getResponseFromIntrospector(inventoryItems, aaiExtMap.getHttpHeaders()); + } + success = true; + } catch (AAIException e) { + success = false; + throw e; + } catch (Exception e) { + success = false; + throw new AAIException("AAI_5105", e); + } finally { + if (dbEngine != null) { + if (success) { + dbEngine.commit(); + } else { + dbEngine.rollback(); + } + } + } + + return response; + } + + private Response getResponseFromIntrospector(Introspector obj, HttpHeaders headers) { + boolean isJson = false; + for (MediaType mt : headers.getAcceptableMediaTypes()) { + if (MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) { + isJson = true; + break; + } + } + org.onap.aai.introspection.MarshallerProperties properties; + if (isJson) { + properties = new org.onap.aai.introspection.MarshallerProperties.Builder( + org.onap.aai.restcore.MediaType.APPLICATION_JSON_TYPE).build(); + } else { + properties = new org.onap.aai.introspection.MarshallerProperties.Builder( + org.onap.aai.restcore.MediaType.APPLICATION_XML_TYPE).build(); + } + + String marshalledObj = obj.marshal(properties); + return Response.ok().entity(marshalledObj).build(); + } + + /** + * Map instance filters. + * + * @param instanceFilters the instance filters + * @param startNodeFilterHash the start node filter hash + * @param jaxbContext the jaxb context + * @return the string + */ + private String mapInstanceFilters(DynamicEntity instanceFilters, List<Map<String, Object>> startNodeFilterHash, + DynamicJAXBContext jaxbContext) { + + if (instanceFilters == null || !instanceFilters.isSet("instanceFilter")) { + return null; + } + @SuppressWarnings("unchecked") + List<DynamicEntity> instanceFilter = (ArrayList<DynamicEntity>) instanceFilters.get("instanceFilter"); + String resourceVersion = null; + + for (DynamicEntity instFilt : instanceFilter) { + List<DynamicEntity> any = instFilt.get("any"); + HashMap<String, Object> thisNodeFilterHash = new HashMap<String, Object>(); + for (DynamicEntity anyEnt : any) { + String clazz = anyEnt.getClass().getCanonicalName(); + String simpleClazz = anyEnt.getClass().getSimpleName(); + + String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz); + + DynamicType anyEntType = jaxbContext.getDynamicType(clazz); + + for (String propName : anyEntType.getPropertiesNames()) { + // hyphencase the prop and throw it on the hash + if (anyEnt.isSet(propName)) { + thisNodeFilterHash.put( + nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), + anyEnt.get(propName)); + if (propName.equals("resourceVersion") && resourceVersion == null) { + resourceVersion = (String) anyEnt.get(propName); + } + } + } + } + startNodeFilterHash.add(thisNodeFilterHash); + } + return resourceVersion; + } + + /** + * Map secondary filters. + * + * @param secondaryFilts the secondary filters + * @param secondaryFilterHash the secondary filter hash + * @param jaxbContext the jaxb context + * @return the string + */ + private void mapSecondaryFilters(DynamicEntity secondaryFilts, Map<String, Object> secondaryFilterHash, + DynamicJAXBContext jaxbContext) { + + if (secondaryFilts == null || !secondaryFilts.isSet("secondaryFilt")) { + return; + } + @SuppressWarnings("unchecked") + List<DynamicEntity> secondaryFilter = (ArrayList<DynamicEntity>) secondaryFilts.get("secondaryFilt"); + + for (DynamicEntity secondaryFilt : secondaryFilter) { + List<DynamicEntity> any = secondaryFilt.get("any"); + + for (DynamicEntity anyEnt : any) { + String clazz = anyEnt.getClass().getCanonicalName(); + String simpleClazz = anyEnt.getClass().getSimpleName(); + + String nodeType = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, simpleClazz); + + DynamicType anyEntType = jaxbContext.getDynamicType(clazz); + + for (String propName : anyEntType.getPropertiesNames()) { + // hyphencase the prop and throw it on the hash + if (anyEnt.isSet(propName)) { + secondaryFilterHash.put( + nodeType + "." + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName), + anyEnt.get(propName)); + } + } + } + } + } + + /** + * Remap inventory items. + * + * @param invResultItem the inv result item + * @param jaxbContext the jaxb context + * @param includeTheseVertices the include these vertices + * @param objectToVertMap the object to vert map + * @param aaiExtMap the aai ext map + * @return the dynamic entity + */ + private DynamicEntity remapInventoryItems(DynamicEntity invResultItem, DynamicJAXBContext jaxbContext, + Map<String, String> includeTheseVertices, Map<Object, String> objectToVertMap, AAIExtensionMap aaiExtMap) { + + + DynamicEntity inventoryItem = jaxbContext + .newDynamicEntity("inventory.aai.onap.org." + aaiExtMap.getApiVersion() + ".InventoryResponseItem"); + Object item = invResultItem.get("item"); + inventoryItem.set("modelName", invResultItem.get("modelName")); + inventoryItem.set("item", item); + inventoryItem.set("extraProperties", invResultItem.get("extraProperties")); + + String vertexId = ""; + + if (objectToVertMap.containsKey(item)) { + vertexId = objectToVertMap.get(item); + } + + if (includeTheseVertices.containsKey(vertexId)) { + if (invResultItem.isSet("inventoryResponseItems")) { + List<DynamicEntity> invItemList = new ArrayList<DynamicEntity>(); + DynamicEntity inventoryItems = jaxbContext.newDynamicEntity( + "inventory.aai.att.com." + aaiExtMap.getApiVersion() + ".InventoryResponseItems"); + DynamicEntity subInventoryResponseItems = invResultItem.get("inventoryResponseItems"); + List<DynamicEntity> subInventoryResponseItemList = + subInventoryResponseItems.get("inventoryResponseItem"); + for (DynamicEntity ent : subInventoryResponseItemList) { + DynamicEntity invItem = + remapInventoryItems(ent, jaxbContext, includeTheseVertices, objectToVertMap, aaiExtMap); + if (invItem != null) { + invItemList.add(invItem); + } + } + inventoryItems.set("inventoryResponseItem", invItemList); + inventoryItem.set("inventoryResponseItems", inventoryItems); + } + } + return inventoryItem; + } + + /** + * Unpack result set. + * + * @param g the g + * @param resultSetList the result set list + * @param jaxbContext the jaxb context + * @param aaiResources the aai resources + * @param objectToVertMap the object to vert map + * @param aaiExtMap the aai ext map + * @return the array list + * @throws AAIException the AAI exception + */ + // this should return an inventoryItem + private List<Object> unpackResultSet(List<ResultSet> resultSetList, TransactionalGraphEngine engine, Loader loader, + DBSerializer serializer) throws AAIException { + + List<Object> resultList = new ArrayList<>(); + + for (ResultSet resultSet : resultSetList) { + + if (resultSet.getVert() == null) { + continue; + } + + Introspector inventoryItem = loader.introspectorFromName("inventory-response-item"); + Introspector inventoryItems = loader.introspectorFromName("inventory-response-items"); + // add this inventoryItem to the resultList for this level + resultList.add(inventoryItem.getUnderlyingObject()); + + Vertex vert = resultSet.getVert(); + + String aaiNodeType = vert.<String>property("aai-node-type").orElse(null); + + if (aaiNodeType != null) { + Introspector thisObj = loader.introspectorFromName(aaiNodeType); + + if (resultSet.getExtraPropertyHash() != null) { + Map<String, Object> extraProperties = resultSet.getExtraPropertyHash(); + + Introspector extraPropertiesEntity = loader.introspectorFromName("extra-properties"); + + List<Object> extraPropsList = extraPropertiesEntity.getValue("extra-property"); + + for (Map.Entry<String, Object> ent : extraProperties.entrySet()) { + String propName = ent.getKey(); + Object propVal = ent.getValue(); + + Introspector extraPropEntity = loader.introspectorFromName("extra-property"); + + extraPropEntity.setValue("property-name", propName); + extraPropEntity.setValue("property-value", propVal); + + extraPropsList.add(extraPropEntity.getUnderlyingObject()); + + } + inventoryItem.setValue("extra-properties", extraPropertiesEntity.getUnderlyingObject()); + } + + try { + serializer.dbToObject(Collections.singletonList(vert), thisObj, 0, true, "false"); + } catch (UnsupportedEncodingException e1) { + throw new AAIException("AAI_5105"); + } + PropertyLimitDesc propertyLimitDesc = resultSet.getPropertyLimitDesc(); + + if (propertyLimitDesc != null) { + + if (PropertyLimitDesc.SHOW_NONE.equals(propertyLimitDesc)) { + HashMap<String, Object> emptyPropertyOverRideHash = new HashMap<String, Object>(); + for (String key : thisObj.getAllKeys()) { + emptyPropertyOverRideHash.put(key, null); + } + filterProperties(thisObj, emptyPropertyOverRideHash); + } else if (PropertyLimitDesc.SHOW_ALL.equals(propertyLimitDesc)) { + // keep everything + } else if (PropertyLimitDesc.SHOW_NAME_AND_KEYS_ONLY.equals(propertyLimitDesc)) { + HashMap<String, Object> keysAndNamesPropHash = new HashMap<String, Object>(); + + for (String key : thisObj.getAllKeys()) { + keysAndNamesPropHash.put(key, null); + } + String namePropMetaData = thisObj.getMetadata(ObjectMetadata.NAME_PROPS); + if (namePropMetaData != null) { + String[] nameProps = namePropMetaData.split(","); + for (String names : nameProps) { + keysAndNamesPropHash.put(names, null); + } + } + filterProperties(thisObj, keysAndNamesPropHash); + } + } else { + if (resultSet.getPropertyOverRideHash() != null && resultSet.getPropertyOverRideHash().size() > 0) { + Map<String, Object> propertyOverRideHash = resultSet.getPropertyOverRideHash(); + if (propertyOverRideHash.containsKey("persona-model-id")) { + propertyOverRideHash.remove("persona-model-id"); + propertyOverRideHash.put("model-invariant-id", null); + } + for (String key : thisObj.getAllKeys()) { + propertyOverRideHash.put(key, null); + } + filterProperties(thisObj, propertyOverRideHash); + } else { + // keep everything + } + } + + if (thisObj != null) { + inventoryItem.setValue("item", thisObj.getUnderlyingObject()); + + String modelName = null; + try { + // Try to get the modelName if we can. Otherwise, do not fail, just return what we have already. + String modelInvariantIdLocal = + (String) vert.<String>property("model-invariant-id-local").orElse(null); // this one + // points at a + // model + String modelVersionIdLocal = + (String) vert.<String>property("model-version-id-local").orElse(null); // this one + // points at a + // model-ver + + if ((modelInvariantIdLocal != null && modelVersionIdLocal != null) + && (modelInvariantIdLocal.length() > 0 && modelVersionIdLocal.length() > 0)) { + Introspector modelVer = loader.introspectorFromName("model-ver"); + modelVer.setValue("model-version-id", modelVersionIdLocal); + QueryBuilder builder = engine.getQueryBuilder().createDBQuery(modelVer); + List<Vertex> modelVerVerts = builder.toList(); + if ((modelVerVerts != null) && (modelVerVerts.size() == 1)) { + Vertex modelVerVert = modelVerVerts.get(0); + modelName = modelVerVert.<String>property("model-name").orElse(null); + if (modelName != null && modelName.length() > 0) { + inventoryItem.setValue("model-name", modelName); + } + } + } + } catch (DynamicException e) { + ; // it's ok, dynamic object might not have these fields + } catch (Exception e) { + ; // it's ok, couldn't find a matching model + } + + if (resultSet.getSubResultSet() != null) { + List<ResultSet> subResultSet = resultSet.getSubResultSet(); + if (subResultSet != null && subResultSet.size() > 0) { + List<Object> res = unpackResultSet(subResultSet, engine, loader, serializer); + if (res.size() > 0) { + inventoryItems.setValue("inventory-response-item", res); + inventoryItem.setValue("inventory-response-items", + inventoryItems.getUnderlyingObject()); + } + } + } + } + } + } + + return resultList; + } + + private void filterProperties(Introspector thisObj, Map<String, Object> override) { + + thisObj.getProperties().stream().filter(x -> { + return !override.containsKey(x); + }).forEach(prop -> { + if (thisObj.isSimpleType(prop)) { + thisObj.setValue(prop, null); + } + }); + + } + + /** + * Gets the media type. + * + * @param mediaTypeList the media type list + * @return the media type + */ + protected String getMediaType(List<MediaType> mediaTypeList) { + String mediaType = MediaType.APPLICATION_JSON; // json is the default + for (MediaType mt : mediaTypeList) { + if (MediaType.APPLICATION_XML_TYPE.isCompatible(mt)) { + mediaType = MediaType.APPLICATION_XML; + } + } + return mediaType; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java index f61e342..8c97c0a 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/SearchProvider.java @@ -22,7 +22,6 @@ package org.onap.aai.rest.search; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; - import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -35,7 +34,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; - import org.onap.aai.dbgraphmap.SearchGraph; import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; @@ -54,304 +52,262 @@ import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; -import org.onap.aai.util.AAIConstants; +import org.onap.aai.util.GenericQueryBuilder; +import org.onap.aai.util.NodesQueryBuilder; import org.onap.aai.util.TraversalConstants; import org.springframework.beans.factory.annotation.Autowired; import org.onap.aai.concurrent.AaiCallable; - import com.att.eelf.configuration.EELFLogger; import com.att.eelf.configuration.EELFManager; import org.springframework.beans.factory.annotation.Value; /** - * Implements the search subdomain in the REST API. All API calls must include - * X-FromAppId and X-TransactionId in the header. + * Implements the search subdomain in the REST API. All API calls must include X-FromAppId and + * X-TransactionId in the header. */ @Path("/{version: v[1-9][0-9]*|latest}/search") public class SearchProvider extends RESTAPI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchProvider.class); - - public static final String GENERIC_QUERY = "/generic-query"; - - public static final String NODES_QUERY = "/nodes-query"; - - public static final String TARGET_ENTITY = "DB"; - - private SearchGraph searchGraph; - - private LoaderFactory loaderFactory; - - private SchemaVersions schemaVersions; - - private String basePath; - - @Autowired - public SearchProvider( - LoaderFactory loaderFactory, - SearchGraph searchGraph, - SchemaVersions schemaVersions, - @Value("${schema.uri.base.path}") String basePath - ){ - this.loaderFactory = loaderFactory; - this.searchGraph = searchGraph; - this.schemaVersions = schemaVersions; - this.basePath = basePath; - } - - /** - * Gets the generic query response. - * - * @param headers the headers - * @param req the req - * @param startNodeType the start node type - * @param startNodeKeyParams the start node key params - * @param includeNodeTypes the include node types - * @param depth the depth - * @return the generic query response - */ - /* ---------------- Start Generic Query --------------------- */ - @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Path(GENERIC_QUERY) - public Response getGenericQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - @QueryParam("start-node-type") final String startNodeType, - @QueryParam("key") final List<String> startNodeKeyParams, - @QueryParam("include") final List<String> includeNodeTypes, - @QueryParam("depth") final int depth, - @PathParam("version")String versionParam, - @Context UriInfo info - ) { - return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, - headers, - info, - HttpMethod.GET, - new AaiCallable<Response>() { - @Override - public Response process() { - return processGenericQueryResponse(headers, req, startNodeType, startNodeKeyParams, includeNodeTypes, depth, versionParam); - } - } - ); - } - - public Response processGenericQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - @QueryParam("start-node-type") final String startNodeType, - @QueryParam("key") final List<String> startNodeKeyParams, - @QueryParam("include") final List<String> includeNodeTypes, - @QueryParam("depth") final int depth, - @PathParam("version")String versionParam - ) { - - String methodName = "getGenericQueryResponse"; - AAIException ex = null; - Response searchResult = null; - String fromAppId = null; - String transId = null; - String rqstTm = genDate(); - ArrayList<String> templateVars = new ArrayList<String>(); - double dbTimeMsecs = 0; - try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - - fromAppId = getFromAppId(headers); - transId = getTransId(headers); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); - //only consider header value for search - DBConnectionType type = this.determineConnectionType("force-cache", realTime); - - final SchemaVersion version = new SchemaVersion(versionParam); - - final ModelType factoryType = ModelType.MOXY; - Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); - TransactionalGraphEngine dbEngine = new JanusGraphDBEngine( - QueryStyle.TRAVERSAL, - type, - loader); - DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); - UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - LoggingContext.startTime(); - StopWatch.conditionalStart(); - searchResult = searchGraph.runGenericQuery( - headers, - startNodeType, - startNodeKeyParams, - includeNodeTypes, - depth, - dbEngine, - loader, - urlBuilder - - ); - dbTimeMsecs += StopWatch.stopIfStarted(); - - LoggingContext.successStatusFields(); - LoggingContext.elapsedTime((long)dbTimeMsecs,TimeUnit.MILLISECONDS); - - LOGGER.info ("Completed"); - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); - - String respTm = genDate(); - - } catch (AAIException e) { - LoggingContext.restoreIfPossible(); - // send error response - ex = e; - templateVars.add("GET Search"); - templateVars.add("getGenericQueryResponse"); - searchResult = Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } catch (Exception e) { - LoggingContext.restoreIfPossible(); - // send error response - ex = new AAIException("AAI_4000", e); - templateVars.add("GET Search"); - templateVars.add("getGenericQueryResponse"); - searchResult = Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } finally { - // log success or failure - if (ex != null){ - ErrorLogHelper.logException(ex); - } - } - - return searchResult; - } - - /* ---------------- End Generic Query --------------------- */ - - /** - * Gets the nodes query response. - * - * @param headers the headers - * @param req the req - * @param searchNodeType the search node type - * @param edgeFilterList the edge filter list - * @param filterList the filter list - * @return the nodes query response - */ - /* ---------------- Start Nodes Query --------------------- */ - @GET - @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) - @Path(NODES_QUERY) - public Response getNodesQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - @QueryParam("search-node-type") final String searchNodeType, - @QueryParam("edge-filter") final List<String> edgeFilterList, - @QueryParam("filter") final List<String> filterList, - @PathParam("version")String versionParam, - @Context UriInfo info) - - { - return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, - TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, - headers, - info, - HttpMethod.GET, - new AaiCallable<Response>() { - @Override - public Response process() { - return processNodesQueryResponse(headers, req, searchNodeType, edgeFilterList, filterList, versionParam); - } - } - ); - } - public Response processNodesQueryResponse(@Context HttpHeaders headers, - @Context HttpServletRequest req, - @QueryParam("search-node-type") final String searchNodeType, - @QueryParam("edge-filter") final List<String> edgeFilterList, - @QueryParam("filter") final List<String> filterList, - @PathParam("version")String versionParam) { - String methodName = "getNodesQueryResponse"; - AAIException ex = null; - Response searchResult = null; - String fromAppId = null; - String transId = null; - String rqstTm = genDate(); - ArrayList<String> templateVars = new ArrayList<String>(); - double dbTimeMsecs = 0; - try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - - fromAppId = getFromAppId(headers); - transId = getTransId(headers); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); - //only consider header value for search - DBConnectionType type = this.determineConnectionType("force-cache", realTime); - - final SchemaVersion version = new SchemaVersion(versionParam); - - final ModelType factoryType = ModelType.MOXY; - Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); - TransactionalGraphEngine dbEngine = new JanusGraphDBEngine( - QueryStyle.TRAVERSAL, - type, - loader); - DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); - UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - - LoggingContext.startTime(); - StopWatch.conditionalStart(); - searchResult = searchGraph.runNodesQuery(headers, - searchNodeType, - edgeFilterList, - filterList, - dbEngine, - loader, - urlBuilder); - dbTimeMsecs += StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long)dbTimeMsecs,TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - LOGGER.info ("Completed"); - - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); - - String respTm = genDate(); - } catch (AAIException e) { - LoggingContext.restoreIfPossible(); - // send error response - ex = e; - templateVars.add("GET Search"); - templateVars.add("getNodesQueryResponse"); - searchResult = Response - .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) - .build(); - } catch (Exception e) { - LoggingContext.restoreIfPossible(); - // send error response - ex = new AAIException("AAI_4000", e); - templateVars.add("GET Search"); - templateVars.add("getNodesQueryResponse"); - searchResult = Response - .status(Status.INTERNAL_SERVER_ERROR) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) - .build(); - } finally { - // log success or failure - if (ex != null){ - ErrorLogHelper.logException(ex); - } - } - return searchResult; - } - - - + private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchProvider.class); + + public static final String GENERIC_QUERY = "/generic-query"; + + public static final String NODES_QUERY = "/nodes-query"; + + public static final String TARGET_ENTITY = "DB"; + + private SearchGraph searchGraph; + + private LoaderFactory loaderFactory; + + private SchemaVersions schemaVersions; + + private String basePath; + + @Autowired + public SearchProvider(LoaderFactory loaderFactory, SearchGraph searchGraph, SchemaVersions schemaVersions, + @Value("${schema.uri.base.path}") String basePath) { + this.loaderFactory = loaderFactory; + this.searchGraph = searchGraph; + this.schemaVersions = schemaVersions; + this.basePath = basePath; + } + + /** + * Gets the generic query response. + * + * @param headers the headers + * @param req the req + * @param startNodeType the start node type + * @param startNodeKeyParams the start node key params + * @param includeNodeTypes the include node types + * @param depth the depth + * @return the generic query response + */ + /* ---------------- Start Generic Query --------------------- */ + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Path(GENERIC_QUERY) + public Response getGenericQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("start-node-type") final String startNodeType, + @QueryParam("key") final List<String> startNodeKeyParams, + @QueryParam("include") final List<String> includeNodeTypes, @QueryParam("depth") final int depth, + @PathParam("version") String versionParam, @Context UriInfo info) { + return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, headers, info, HttpMethod.GET, + new AaiCallable<Response>() { + @Override + public Response process() { + return processGenericQueryResponse(headers, req, startNodeType, startNodeKeyParams, + includeNodeTypes, depth, versionParam); + } + }); + } + + public Response processGenericQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("start-node-type") final String startNodeType, + @QueryParam("key") final List<String> startNodeKeyParams, + @QueryParam("include") final List<String> includeNodeTypes, @QueryParam("depth") final int depth, + @PathParam("version") String versionParam) { + + String methodName = "getGenericQueryResponse"; + AAIException ex = null; + Response searchResult = null; + String fromAppId = null; + String transId = null; + String rqstTm = genDate(); + ArrayList<String> templateVars = new ArrayList<String>(); + double dbTimeMsecs = 0; + try { + LoggingContext.save(); + LoggingContext.targetEntity(TARGET_ENTITY); + LoggingContext.targetServiceName(methodName); + + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + String realTime = headers.getRequestHeaders().getFirst("Real-Time"); + // only consider header value for search + DBConnectionType type = this.determineConnectionType("force-cache", realTime); + + final SchemaVersion version = new SchemaVersion(versionParam); + + final ModelType factoryType = ModelType.MOXY; + Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); + TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, type, loader); + DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); + UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); + LoggingContext.startTime(); + StopWatch.conditionalStart(); + searchResult = searchGraph + .runGenericQuery(new GenericQueryBuilder().setHeaders(headers).setStartNodeType(startNodeType) + .setStartNodeKeyParams(startNodeKeyParams).setIncludeNodeTypes(includeNodeTypes) + .setDepth(depth).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); + dbTimeMsecs += StopWatch.stopIfStarted(); + + LoggingContext.successStatusFields(); + LoggingContext.elapsedTime((long) dbTimeMsecs, TimeUnit.MILLISECONDS); + + LOGGER.info("Completed"); + LoggingContext.restoreIfPossible(); + LoggingContext.successStatusFields(); + + String respTm = genDate(); + + } catch (AAIException e) { + LoggingContext.restoreIfPossible(); + // send error response + ex = e; + templateVars.add("GET Search"); + templateVars.add("getGenericQueryResponse"); + searchResult = Response.status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } catch (Exception e) { + LoggingContext.restoreIfPossible(); + // send error response + ex = new AAIException("AAI_4000", e); + templateVars.add("GET Search"); + templateVars.add("getGenericQueryResponse"); + searchResult = Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } finally { + // log success or failure + if (ex != null) { + ErrorLogHelper.logException(ex); + } + } + + return searchResult; + } + + /* ---------------- End Generic Query --------------------- */ + + /** + * Gets the nodes query response. + * + * @param headers the headers + * @param req the req + * @param searchNodeType the search node type + * @param edgeFilterList the edge filter list + * @param filterList the filter list + * @return the nodes query response + */ + /* ---------------- Start Nodes Query --------------------- */ + @GET + @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + @Path(NODES_QUERY) + public Response getNodesQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("search-node-type") final String searchNodeType, + @QueryParam("edge-filter") final List<String> edgeFilterList, + @QueryParam("filter") final List<String> filterList, @PathParam("version") String versionParam, + @Context UriInfo info) + + { + return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, headers, info, HttpMethod.GET, + new AaiCallable<Response>() { + @Override + public Response process() { + return processNodesQueryResponse(headers, req, searchNodeType, edgeFilterList, filterList, + versionParam); + } + }); + } + + public Response processNodesQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, + @QueryParam("search-node-type") final String searchNodeType, + @QueryParam("edge-filter") final List<String> edgeFilterList, + @QueryParam("filter") final List<String> filterList, @PathParam("version") String versionParam) { + String methodName = "getNodesQueryResponse"; + AAIException ex = null; + Response searchResult = null; + String fromAppId = null; + String transId = null; + String rqstTm = genDate(); + ArrayList<String> templateVars = new ArrayList<String>(); + double dbTimeMsecs = 0; + try { + LoggingContext.save(); + LoggingContext.targetEntity(TARGET_ENTITY); + LoggingContext.targetServiceName(methodName); + + fromAppId = getFromAppId(headers); + transId = getTransId(headers); + String realTime = headers.getRequestHeaders().getFirst("Real-Time"); + // only consider header value for search + DBConnectionType type = this.determineConnectionType("force-cache", realTime); + + final SchemaVersion version = new SchemaVersion(versionParam); + + final ModelType factoryType = ModelType.MOXY; + Loader loader = loaderFactory.createLoaderForVersion(factoryType, version); + TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, type, loader); + DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); + UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); + + LoggingContext.startTime(); + StopWatch.conditionalStart(); + searchResult = searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(headers) + .setTargetNodeType(searchNodeType).setEdgeFilterParams(edgeFilterList).setFilterParams(filterList) + .setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); + + dbTimeMsecs += StopWatch.stopIfStarted(); + LoggingContext.elapsedTime((long) dbTimeMsecs, TimeUnit.MILLISECONDS); + LoggingContext.successStatusFields(); + LOGGER.info("Completed"); + + LoggingContext.restoreIfPossible(); + LoggingContext.successStatusFields(); + + String respTm = genDate(); + } catch (AAIException e) { + LoggingContext.restoreIfPossible(); + // send error response + ex = e; + templateVars.add("GET Search"); + templateVars.add("getNodesQueryResponse"); + searchResult = Response.status(e.getErrorObject().getHTTPResponseCode()) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) + .build(); + } catch (Exception e) { + LoggingContext.restoreIfPossible(); + // send error response + ex = new AAIException("AAI_4000", e); + templateVars.add("GET Search"); + templateVars.add("getNodesQueryResponse"); + searchResult = Response.status(Status.INTERNAL_SERVER_ERROR) + .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), ex, templateVars)) + .build(); + } finally { + // log success or failure + if (ex != null) { + ErrorLogHelper.logException(ex); + } + } + return searchResult; + } + + + } diff --git a/aai-traversal/src/main/java/org/onap/aai/util/GenericQueryBuilder.java b/aai-traversal/src/main/java/org/onap/aai/util/GenericQueryBuilder.java new file mode 100644 index 0000000..8570fe4 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/util/GenericQueryBuilder.java @@ -0,0 +1,114 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Samsung Electronics Co., Ltd. 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.aai.util; + +import javax.ws.rs.core.HttpHeaders; +import java.util.List; +import org.onap.aai.introspection.Loader; +import org.onap.aai.serialization.queryformats.utils.UrlBuilder; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +/** + * Builder Class used to minimize number of formal parameters. + */ + +public class GenericQueryBuilder { + + private HttpHeaders headers; + private String startNodeType; + private List<String> startNodeKeyParams; + private List<String> includeNodeTypes; + private int depth; + private TransactionalGraphEngine dbEngine; + private Loader loader; + private UrlBuilder urlBuilder; + + public HttpHeaders getHeaders() { + return headers; + } + + public String getStartNodeType() { + return startNodeType; + } + + public List<String> getStartNodeKeyParams() { + return startNodeKeyParams; + } + + public List<String> getIncludeNodeTypes() { + return includeNodeTypes; + } + + public int getDepth() { + return depth; + } + + public TransactionalGraphEngine getDbEngine() { + return dbEngine; + } + + public Loader getLoader() { + return loader; + } + + public UrlBuilder getUrlBuilder() { + return urlBuilder; + } + + public GenericQueryBuilder setHeaders(HttpHeaders headers) { + this.headers = headers; + return this; + } + + public GenericQueryBuilder setStartNodeType(String startNodeType) { + this.startNodeType = startNodeType; + return this; + } + + public GenericQueryBuilder setStartNodeKeyParams(List<String> startNodeKeyParams) { + this.startNodeKeyParams = startNodeKeyParams; + return this; + } + + public GenericQueryBuilder setIncludeNodeTypes(List<String> includeNodeTypes) { + this.includeNodeTypes = includeNodeTypes; + return this; + } + + public GenericQueryBuilder setDepth(int depth) { + this.depth = depth; + return this; + } + + public GenericQueryBuilder setDbEngine(TransactionalGraphEngine dbEngine) { + this.dbEngine = dbEngine; + return this; + } + + public GenericQueryBuilder setLoader(Loader loader) { + this.loader = loader; + return this; + } + + public GenericQueryBuilder setUrlBuilder(UrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + return this; + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/util/NodesQueryBuilder.java b/aai-traversal/src/main/java/org/onap/aai/util/NodesQueryBuilder.java new file mode 100644 index 0000000..978e484 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/util/NodesQueryBuilder.java @@ -0,0 +1,106 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Samsung Electronics Co., Ltd. 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.util; + +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import javax.ws.rs.core.HttpHeaders; +import java.util.List; +import org.onap.aai.introspection.Loader; +import org.onap.aai.serialization.queryformats.utils.UrlBuilder; + +/** + * Builder Class used to minimize number of formal parameters. + */ + +public class NodesQueryBuilder { + + private HttpHeaders headers; + private List<String> edgeFilterParams; + private List<String> filterParams; + private TransactionalGraphEngine dbEngine; + private Loader loader; + private UrlBuilder urlBuilder; + private String targetNodeType; + + public HttpHeaders getHeaders() { + return headers; + } + + public NodesQueryBuilder setHeaders(HttpHeaders headers) { + this.headers = headers; + return this; + } + + public String getTargetNodeType() { + return targetNodeType; + } + + public NodesQueryBuilder setTargetNodeType(String targetNodeType) { + this.targetNodeType = targetNodeType; + return this; + } + + public List<String> getEdgeFilterParams() { + return edgeFilterParams; + } + + public NodesQueryBuilder setEdgeFilterParams(List<String> edgeFilterParams) { + this.edgeFilterParams = edgeFilterParams; + return this; + } + + public List<String> getFilterParams() { + return filterParams; + } + + public NodesQueryBuilder setFilterParams(List<String> filterParams) { + this.filterParams = filterParams; + return this; + } + + public TransactionalGraphEngine getDbEngine() { + return dbEngine; + } + + public NodesQueryBuilder setDbEngine(TransactionalGraphEngine dbEngine) { + this.dbEngine = dbEngine; + return this; + } + + public Loader getLoader() { + return loader; + } + + public NodesQueryBuilder setLoader(Loader loader) { + this.loader = loader; + return this; + } + + public UrlBuilder getUrlBuilder() { + return urlBuilder; + } + + public NodesQueryBuilder setUrlBuilder(UrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + return this; + } + +} diff --git a/aai-traversal/src/test/java/org/onap/aai/dbgraphmap/SearchGraphTest.java b/aai-traversal/src/test/java/org/onap/aai/dbgraphmap/SearchGraphTest.java index a048ffc..94a89a9 100644 --- a/aai-traversal/src/test/java/org/onap/aai/dbgraphmap/SearchGraphTest.java +++ b/aai-traversal/src/test/java/org/onap/aai/dbgraphmap/SearchGraphTest.java @@ -41,6 +41,8 @@ import org.onap.aai.serialization.engines.JanusGraphDBEngine; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.utils.UrlBuilder; import org.onap.aai.setup.SchemaVersion; +import org.onap.aai.util.GenericQueryBuilder; +import org.onap.aai.util.NodesQueryBuilder; import javax.servlet.http.HttpServletRequest; @@ -91,14 +93,14 @@ public class SearchGraphTest extends AAISetup{ private TransactionalGraphEngine dbEngine; @Before - public void setup(){ + public void setup() { version = schemaVersions.getDefaultVersion(); - httpHeaders = mock(HttpHeaders.class); - uriInfo = mock(UriInfo.class); + httpHeaders = mock(HttpHeaders.class); + uriInfo = mock(UriInfo.class); - headersMultiMap = new MultivaluedHashMap<>(); - queryParameters = Mockito.spy(new MultivaluedHashMap<>()); + headersMultiMap = new MultivaluedHashMap<>(); + queryParameters = Mockito.spy(new MultivaluedHashMap<>()); headersMultiMap.add("X-FromAppId", "JUNIT"); headersMultiMap.add("X-TransactionId", UUID.randomUUID().toString()); @@ -128,25 +130,24 @@ public class SearchGraphTest extends AAISetup{ when(httpHeaders.getMediaType()).thenReturn(APPLICATION_JSON); loader = loaderFactory.createLoaderForVersion(introspectorFactoryType, version); - dbEngine = new JanusGraphDBEngine( - queryStyle, - type, - loader); + dbEngine = new JanusGraphDBEngine(queryStyle, type, loader); } @Test(expected = AAIException.class) public void runNodesQuery() throws AAIException{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - searchGraph.runNodesQuery(httpHeaders,"",null, - null,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery( + new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("").setEdgeFilterParams(null) + .setFilterParams(null).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } @Test(expected = AAIException.class) public void runNodesQueryNull() throws AAIException{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - searchGraph.runNodesQuery(httpHeaders,"nnn",null, - null,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery( + new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("nnn").setEdgeFilterParams(null) + .setFilterParams(null).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } @Test(expected = AAIException.class) public void testRunGenericQueryFailWhenInvalidRelationshipList() throws AAIException { @@ -159,7 +160,9 @@ public class SearchGraphTest extends AAISetup{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - Response response = searchGraph.runGenericQuery(httpHeaders, "service-instance", keys, includeStrings, 1, dbEngine, loader, urlBuilder); + Response response = searchGraph.runGenericQuery(new GenericQueryBuilder().setHeaders(httpHeaders) + .setStartNodeType("service-instance").setStartNodeKeyParams(keys).setIncludeNodeTypes(includeStrings) + .setDepth(1).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); System.out.println(response); } @@ -175,7 +178,9 @@ public class SearchGraphTest extends AAISetup{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - Response response = searchGraph.runGenericQuery(httpHeaders, null, keys, includeStrings, 1, dbEngine, loader, urlBuilder); + Response response = searchGraph.runGenericQuery(new GenericQueryBuilder().setHeaders(httpHeaders) + .setStartNodeType(null).setStartNodeKeyParams(keys).setIncludeNodeTypes(includeStrings).setDepth(1) + .setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); System.out.println(response); } @@ -190,7 +195,9 @@ public class SearchGraphTest extends AAISetup{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - Response response = searchGraph.runGenericQuery(httpHeaders, "", null, includeStrings, 1, dbEngine, loader, urlBuilder); + Response response = searchGraph.runGenericQuery(new GenericQueryBuilder().setHeaders(httpHeaders) + .setStartNodeType("").setStartNodeKeyParams(null).setIncludeNodeTypes(includeStrings).setDepth(1) + .setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); System.out.println(response); } @@ -205,7 +212,9 @@ public class SearchGraphTest extends AAISetup{ DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, "JUNIT"); UrlBuilder urlBuilder = new UrlBuilder(version, serializer, schemaVersions, basePath); - Response response = searchGraph.runGenericQuery(httpHeaders, "", keys, null, 1, dbEngine, loader, urlBuilder); + Response response = searchGraph.runGenericQuery(new GenericQueryBuilder().setHeaders(httpHeaders) + .setStartNodeType("").setStartNodeKeyParams(keys).setIncludeNodeTypes(null).setDepth(1) + .setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); System.out.println(response); } @@ -310,8 +319,8 @@ public class SearchGraphTest extends AAISetup{ filter.add("model:EQUALS:DOES-NOT-EXIST:AAI"); List<String> edgeFilter=new ArrayList<String>(); edgeFilter.add("model:DOES-NOT-EXIST:DOES-NOT-EXIST:AAI"); - Response response= searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + Response response= searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); Assert.assertNotNull(response); } @@ -322,8 +331,8 @@ public class SearchGraphTest extends AAISetup{ filter.add("model:EQUALS:DOES-NOT-EXIST:AAI"); List<String> edgeFilter=new ArrayList<String>(); edgeFilter.add("model:EXISTS:DOES-NOT-EXIST:AAI"); - Response response= searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + Response response= searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); Assert.assertNotNull(response); } @@ -333,8 +342,8 @@ public class SearchGraphTest extends AAISetup{ List<String> filter=new ArrayList<String>(); filter.add("model:DOES-NOT-EQUAL:DOES-NOT-EXIST"); List<String> edgeFilter=new ArrayList<String>(); - searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } @Test @@ -343,8 +352,8 @@ public class SearchGraphTest extends AAISetup{ List<String> filter=new ArrayList<String>(); filter.add("model:DOES-NOT-EQUAL:DOES-NOT-EXIST:AAI"); List<String> edgeFilter=new ArrayList<String>(); - searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } @Test @@ -353,8 +362,8 @@ public class SearchGraphTest extends AAISetup{ List<String> filter=new ArrayList<String>(); filter.add("model:EXISTS:DOES-NOT-EXIST:AAI"); List<String> edgeFilter=new ArrayList<String>(); - searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } @Test(expected = AAIException.class) @@ -363,7 +372,7 @@ public class SearchGraphTest extends AAISetup{ List<String> filter=new ArrayList<String>(); filter.add("model:DOES_NOT_EXIST:DOES-NOT-EXIST:AAI"); List<String> edgeFilter=new ArrayList<String>(); - searchGraph.runNodesQuery(httpHeaders,"model-ver",edgeFilter, - filter,dbEngine,loader,urlBuilder); + searchGraph.runNodesQuery(new NodesQueryBuilder().setHeaders(httpHeaders).setTargetNodeType("model-ver").setEdgeFilterParams(edgeFilter) + .setFilterParams(filter).setDbEngine(dbEngine).setLoader(loader).setUrlBuilder(urlBuilder)); } } |