diff options
Diffstat (limited to 'aai-traversal/src/main/java/org/onap')
49 files changed, 3200 insertions, 1076 deletions
diff --git a/aai-traversal/src/main/java/org/onap/aai/Profiles.java b/aai-traversal/src/main/java/org/onap/aai/Profiles.java index ea65b9a..25f51c3 100644 --- a/aai-traversal/src/main/java/org/onap/aai/Profiles.java +++ b/aai-traversal/src/main/java/org/onap/aai/Profiles.java @@ -25,7 +25,10 @@ public final class Profiles { public static final String DME2 = "dme2"; public static final String ONE_WAY_SSL = "one-way-ssl"; + // AAF Basic Auth public static final String AAF_AUTHENTICATION = "aaf-auth"; + // AAF Auth with Client Certs + public static final String AAF_CERT_AUTHENTICATION = "aaf-cert-auth"; public static final String TWO_WAY_SSL = "two-way-ssl"; private Profiles(){} diff --git a/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java b/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java index 4d8f4a8..64f99b9 100644 --- a/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java +++ b/aai-traversal/src/main/java/org/onap/aai/TraversalApp.java @@ -19,35 +19,38 @@ */ package org.onap.aai; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.onap.aai.aailog.logs.AaiDebugLog; import org.onap.aai.config.PropertyPasswordConfiguration; import org.onap.aai.config.SpringContextAware; import org.onap.aai.dbmap.AAIGraph; import org.onap.aai.exceptions.AAIException; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.StatusCode; +import org.onap.aai.logging.LogFormatTools; import org.onap.aai.nodes.NodeIngestor; import org.onap.aai.util.AAIConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import org.springframework.core.env.Environment; -import org.slf4j.MDC; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; -import java.util.UUID; + import java.util.Map; -@SpringBootApplication +@SpringBootApplication(exclude = { + DataSourceAutoConfiguration.class, + DataSourceTransactionManagerAutoConfiguration.class, + HibernateJpaAutoConfiguration.class +}) // Component Scan provides a way to look for spring beans // It only searches beans in the following packages // Any method annotated with @Bean annotation or any class @@ -59,17 +62,17 @@ import java.util.Map; "org.onap.aai.tasks", "org.onap.aai.service", "org.onap.aai.rest", - "org.onap.aai.rest-client" -}) - -@EnableAutoConfiguration(exclude = { - DataSourceAutoConfiguration.class, - DataSourceTransactionManagerAutoConfiguration.class, - HibernateJpaAutoConfiguration.class + "org.onap.aai.aaf", + "org.onap.aai.aailog" }) public class TraversalApp { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(TraversalApp.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(TraversalApp.class.getName()); + + private static AaiDebugLog debugLog = new AaiDebugLog(); + static { + debugLog.setupMDC(); + } private static final String APP_NAME = "aai-traversal"; private static Map<String,String> contextMap; @@ -92,26 +95,18 @@ public class TraversalApp { System.setProperty("org.onap.aai.serverStarted", "false"); setDefaultProps(); - LoggingContext.save(); - LoggingContext.component("init"); - LoggingContext.partnerName("NA"); - LoggingContext.targetEntity(APP_NAME); - LoggingContext.requestId(UUID.randomUUID().toString()); - LoggingContext.serviceName(APP_NAME); - LoggingContext.targetServiceName("contextInitialized"); - LoggingContext.statusCode(StatusCode.COMPLETE); contextMap = MDC.getCopyOfContextMap(); - logger.info("AAI Server initialization started..."); + logger.debug("AAI Server initialization started..."); // Setting this property to allow for encoded slash (/) in the path parameter // This is only needed for tomcat keeping this as temporary System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true"); - logger.info("Starting AAIGraph connections and the NodeInjestor"); + logger.debug("Starting AAIGraph connections and the NodeInjestor"); if(env.acceptsProfiles(Profiles.TWO_WAY_SSL) && env.acceptsProfiles(Profiles.ONE_WAY_SSL)){ - logger.warn("You have seriously misconfigured your application"); + logger.debug("You have seriously misconfigured your application"); } AAIConfig.init(); @@ -121,6 +116,9 @@ public class TraversalApp { @PreDestroy public void cleanup(){ + contextMap = MDC.getCopyOfContextMap(); + MDC.setContextMap (contextMap); + logger.debug("Traversal MicroService stopped"); logger.info("Shutting down both realtime and cached connections"); AAIGraph.getInstance().graphShutdown(); } @@ -129,14 +127,6 @@ public class TraversalApp { setDefaultProps(); - LoggingContext.save(); - LoggingContext.component("init"); - LoggingContext.partnerName("NA"); - LoggingContext.targetEntity(APP_NAME); - LoggingContext.requestId(UUID.randomUUID().toString()); - LoggingContext.serviceName(APP_NAME); - LoggingContext.targetServiceName("contextInitialized"); - LoggingContext.statusCode(StatusCode.COMPLETE); Environment env =null; AAIConfig.init(); @@ -149,12 +139,8 @@ public class TraversalApp { } catch(Exception ex){ AAIException aai = schemaServiceExceptionTranslator(ex); - LoggingContext.statusCode(LoggingContext.StatusCode.ERROR); - LoggingContext.responseCode(LoggingContext.DATA_ERROR); - logger.error("Problems starting Traversal "+aai.getMessage()); ErrorLogHelper.logException(aai); ErrorLogHelper.logError(aai.getCode(), ex.getMessage() + ", resolve and restart Traversal"); - //ErrorLogHelper.logError(aai.getCode(), aai.getMessage() + aai.getCause().toString()); throw aai; } @@ -166,8 +152,6 @@ public class TraversalApp { env.getProperty("server.port") ); - logger.info("Traversal MicroService Started"); - logger.error("Traversal MicroService Started"); logger.debug("Traversal MicroService Started"); System.out.println("Traversal Microservice Started"); } @@ -198,22 +182,24 @@ public class TraversalApp { } private static AAIException schemaServiceExceptionTranslator(Exception ex) { AAIException aai = null; - logger.info("Error Message is "+ ExceptionUtils.getRootCause(ex).toString() + " details - "+ExceptionUtils.getRootCause(ex).getMessage()); - if(ExceptionUtils.getRootCause(ex).getMessage().contains("NodeIngestor")){ - aai = new AAIException("AAI_3026","Error reading OXM from SchemaService - Investigate"); - } - else if(ExceptionUtils.getRootCause(ex).getMessage().contains("EdgeIngestor")){ - aai = new AAIException("AAI_3027","Error reading EdgeRules from SchemaService - Investigate"); - } - else if(ExceptionUtils.getRootCause(ex).getMessage().contains("stored-queries")){ - aai = new AAIException("AAI_3027","Error reading EdgeRules from SchemaService - Investigate"); - } - else if(ExceptionUtils.getRootCause(ex).getMessage().contains("Connection refused")){ - aai = new AAIException("AAI_3025","Error connecting to SchemaService - Investigate"); - } - else { - aai = new AAIException("AAI_3025","Error connecting to SchemaService - Please Investigate"); - } + logger.info("Error Message is {} details - {}", ExceptionUtils.getRootCause(ex).toString(), ExceptionUtils.getRootCause(ex).getMessage()); + if ( ExceptionUtils.getRootCause(ex) == null || ExceptionUtils.getRootCause(ex).getMessage() == null ) { + aai = new AAIException("AAI_3025","Error parsing exception - Please Investigate" + + LogFormatTools.getStackTop(ex)); + } else { + logger.info("Exception is " + ExceptionUtils.getRootCause(ex).getMessage() + "Root cause is"+ ExceptionUtils.getRootCause(ex).toString()); + if(ExceptionUtils.getRootCause(ex).getMessage().contains("NodeIngestor")){ + aai = new AAIException("AAI_3026","Error reading OXM from SchemaService - Investigate"); + } + else if(ExceptionUtils.getRootCause(ex).getMessage().contains("EdgeIngestor")){ + aai = new AAIException("AAI_3027","Error reading EdgeRules from SchemaService - Investigate"); + } + else if(ExceptionUtils.getRootCause(ex).getMessage().contains("Connection refused")){ + aai = new AAIException("AAI_3025","Error connecting to SchemaService - Investigate"); + }else { + aai = new AAIException("AAI_3025","Error connecting to SchemaService - Please Investigate"); + } + } return aai; } diff --git a/aai-traversal/src/main/java/org/onap/aai/aailog/logs/AaiDBTraversalMetricLog.java b/aai-traversal/src/main/java/org/onap/aai/aailog/logs/AaiDBTraversalMetricLog.java new file mode 100644 index 0000000..8afc58b --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/aailog/logs/AaiDBTraversalMetricLog.java @@ -0,0 +1,115 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.aailog.logs; + +import org.onap.aai.util.AAIConstants; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.filter.base.MDCSetup; +import org.onap.logging.filter.base.ONAPComponents; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.slf4j.*; +import org.springframework.beans.factory.annotation.Value; + +import java.net.URI; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Optional; + +public class AaiDBTraversalMetricLog extends MDCSetup { + + protected static final Logger logger = LoggerFactory.getLogger(AaiDBTraversalMetricLog.class); + private final String partnerName; + private static final Marker INVOKE_RETURN = MarkerFactory.getMarker("INVOKE-RETURN"); + private static final String TARGET_ENTITY = ONAPComponents.AAI.toString() + ".DB"; + public AaiDBTraversalMetricLog(String subcomponent) { + partnerName = getPartnerName(subcomponent); + } + + + protected String getTargetServiceName(Optional<URI> uri) { + return (getServiceName(uri)); + } + + protected String getServiceName(Optional<URI> uri) { + String serviceName = Constants.DefaultValues.UNKNOWN; + if (uri.isPresent()) { + serviceName = uri.get().getPath(); + if (serviceName != null && (!serviceName.isEmpty())) { + serviceName = serviceName.replaceAll(",", "\\\\,"); + } + } + return serviceName; + } + + + protected String getTargetEntity(Optional<URI> uri) { + return TARGET_ENTITY; + } + + protected String getPartnerName(@Value(AAIConstants.AAI_TRAVERSAL_MS) String subcomponent ) { + StringBuilder sb = new StringBuilder(ONAPComponents.AAI.toString()).append(subcomponent); + return (sb.toString()); + } + + public void pre(Optional<URI> uri) { + try { + setupMDC(uri); + setLogTimestamp(); + logger.info(ONAPLogConstants.Markers.INVOKE, "Invoke"); + } catch (Exception e) { + logger.warn("Error in AaiDBMetricLog pre", e.getMessage()); + } + } + + public void post() { + try { + setLogTimestamp(); + setElapsedTimeInvokeTimestamp(); + setResponseStatusCode(200); + setResponseDescription(200); + MDC.put(ONAPLogConstants.MDCs.RESPONSE_CODE, "200"); + logger.info(INVOKE_RETURN, "InvokeReturn"); + clearClientMDCs(); + } catch (Exception e) { + logger.warn("Error in AaiDBMetricLog post", e.getMessage()); + } + } + + protected void setupMDC(Optional<URI> uri) { + MDC.put("InvokeTimestamp", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT)); + MDC.put("TargetServiceName", this.getTargetServiceName(uri)); + MDC.put("StatusCode", ONAPLogConstants.ResponseStatus.INPROGRESS.toString()); + this.setInvocationIdFromMDC(); + if (MDC.get("TargetEntity") == null) { + String targetEntity = this.getTargetEntity(uri); + if (targetEntity != null) { + MDC.put("TargetEntity", targetEntity); + } else { + MDC.put("TargetEntity", "Unknown-Target-Entity"); + } + } + if (MDC.get("ServiceName") == null) { + MDC.put("ServiceName", this.getServiceName(uri)); + } + this.setServerFQDN(); + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/config/DslConfiguration.java b/aai-traversal/src/main/java/org/onap/aai/config/DslConfiguration.java index 311dd99..d10d4ac 100644 --- a/aai-traversal/src/main/java/org/onap/aai/config/DslConfiguration.java +++ b/aai-traversal/src/main/java/org/onap/aai/config/DslConfiguration.java @@ -19,28 +19,35 @@ */ package org.onap.aai.config; +import org.antlr.v4.runtime.tree.ParseTreeListener; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.introspection.LoaderFactory; -import org.onap.aai.rest.dsl.DslListener; import org.onap.aai.rest.dsl.DslQueryProcessor; +import org.onap.aai.rest.enums.QueryVersion; import org.onap.aai.setup.SchemaVersions; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; +import java.util.HashMap; +import java.util.Map; + @Configuration public class DslConfiguration { @Bean @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public DslListener dslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory){ - return new DslListener(edgeIngestor, schemaVersions, loaderFactory); + public Map<QueryVersion, ParseTreeListener> dslListeners(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory){ + Map<QueryVersion, ParseTreeListener> dslListeners = new HashMap<>(); + dslListeners.put(QueryVersion.V1,new org.onap.aai.rest.dsl.v1.DslListener(edgeIngestor, schemaVersions, loaderFactory)); + dslListeners.put(QueryVersion.V2,new org.onap.aai.rest.dsl.v2.DslListener(edgeIngestor, schemaVersions, loaderFactory)); + return dslListeners; } @Bean @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) - public DslQueryProcessor dslQueryProcessor(DslListener dslListener){ - return new DslQueryProcessor(dslListener); + public DslQueryProcessor dslQueryProcessor(Map<QueryVersion, ParseTreeListener> dslListeners){ + return new DslQueryProcessor(dslListeners); } } diff --git a/aai-traversal/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java b/aai-traversal/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java index 0d2ff88..0a76d6d 100644 --- a/aai-traversal/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java +++ b/aai-traversal/src/main/java/org/onap/aai/config/PropertyPasswordConfiguration.java @@ -29,7 +29,8 @@ import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import org.apache.commons.io.IOUtils; import org.springframework.context.ApplicationContextInitializer; @@ -40,7 +41,7 @@ public class PropertyPasswordConfiguration implements ApplicationContextInitiali private static final Pattern decodePasswordPattern = Pattern.compile("password\\((.*?)\\)"); private PasswordDecoder passwordDecoder = new JettyPasswordDecoder(); - private static final EELFLogger logger = EELFManager.getInstance().getLogger(PropertyPasswordConfiguration.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(PropertyPasswordConfiguration.class.getName()); @Override public void initialize(ConfigurableApplicationContext applicationContext) { @@ -68,10 +69,10 @@ public class PropertyPasswordConfiguration implements ApplicationContextInitiali sslProps.put("server.ssl.key-store-password", keystorePassword); sslProps.put("schema.service.ssl.key-store-password", keystorePassword); } else { - logger.info("Not using AAF Certman password file"); + logger.debug("Not using AAF Certman password file"); } } catch (IOException e) { - logger.warn("Not using AAF Certman password file, e=" + e.getMessage()); + logger.debug("Not using AAF Certman password file, e=" + e.getMessage()); } finally { if (passwordStream != null) { try { @@ -95,10 +96,10 @@ public class PropertyPasswordConfiguration implements ApplicationContextInitiali sslProps.put("server.ssl.trust-store-password", truststorePassword); sslProps.put("schema.service.ssl.trust-store-password", truststorePassword); } else { - logger.info("Not using AAF Certman passphrases file"); + logger.debug("Not using AAF Certman passphrases file"); } } catch (IOException e) { - logger.warn("Not using AAF Certman passphrases file, e=" + e.getMessage()); + logger.debug("Not using AAF Certman passphrases file, e=" + e.getMessage()); } finally { if (passphrasesStream != null) { try { @@ -118,7 +119,7 @@ public class PropertyPasswordConfiguration implements ApplicationContextInitiali } if (!sslProps.isEmpty()) { - logger.info("Using AAF Certman files"); + logger.debug("Using AAF Certman files"); PropertySource<?> additionalProperties = new MapPropertySource("additionalProperties", sslProps); environment.getPropertySources().addFirst(additionalProperties); } diff --git a/aai-traversal/src/main/java/org/onap/aai/config/SearchConfiguration.java b/aai-traversal/src/main/java/org/onap/aai/config/SearchConfiguration.java index 0b8238b..b60a707 100644 --- a/aai-traversal/src/main/java/org/onap/aai/config/SearchConfiguration.java +++ b/aai-traversal/src/main/java/org/onap/aai/config/SearchConfiguration.java @@ -23,7 +23,7 @@ import org.onap.aai.dbgraphmap.SearchGraph; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.introspection.LoaderFactory; -import org.onap.aai.rest.dsl.DslListener; +import org.onap.aai.rest.dsl.v1.DslListener; import org.onap.aai.rest.dsl.DslQueryProcessor; import org.onap.aai.rest.search.CQConfig; import org.onap.aai.rest.search.GremlinServerSingleton; diff --git a/aai-traversal/src/main/java/org/onap/aai/dbgraphgen/ModelBasedProcessing.java b/aai-traversal/src/main/java/org/onap/aai/dbgraphgen/ModelBasedProcessing.java index dc42120..f1ffb9f 100644 --- a/aai-traversal/src/main/java/org/onap/aai/dbgraphgen/ModelBasedProcessing.java +++ b/aai-traversal/src/main/java/org/onap/aai/dbgraphgen/ModelBasedProcessing.java @@ -19,7 +19,9 @@ */ package org.onap.aai.dbgraphgen; -import com.att.eelf.configuration.EELFLogger; +import org.onap.aai.logging.ErrorLogHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; @@ -58,7 +60,7 @@ import java.util.concurrent.TimeUnit; */ public class ModelBasedProcessing { - private EELFLogger LOGGER = EELFManager.getInstance().getLogger(ModelBasedProcessing.class); + private Logger LOGGER = LoggerFactory.getLogger(ModelBasedProcessing.class); private final int MAX_LEVELS = 50; // max depth allowed for our model - to protect against infinite loop problems private TransactionalGraphEngine engine; @@ -842,7 +844,8 @@ public class ModelBasedProcessing { } catch (Exception ex) { // Sometimes things have already been deleted by the time we get to them - just log it. - LOGGER.warn("Exception when trying to delete: " + thisGuyStr + ". msg = " + ex.getMessage() + LogFormatTools.getStackTop(ex)); + AAIException aaiException = new AAIException("AAI_6154", thisGuyStr + ". msg = " + ex.getMessage()); + ErrorLogHelper.logException(aaiException); } if( !gotVtxOK ){ @@ -853,7 +856,7 @@ public class ModelBasedProcessing { } else { if( resSet.getNewDataDelFlag() != null && resSet.getNewDataDelFlag().equals("T") ){ - LOGGER.info(">> will try to delete this one >> " + thisGuyStr); + LOGGER.debug(">> will try to delete this one >> " + thisGuyStr); try { Boolean requireResourceVersion = false; @@ -870,9 +873,10 @@ public class ModelBasedProcessing { throw ae; } else { + ErrorLogHelper.logException(ae); String errText = ae.getErrorObject().getErrorText(); String errDetail = ae.getMessage(); - LOGGER.warn("Exception when deleting " + thisGuyStr + ". ErrorCode = " + errorCode + + LOGGER.debug("Exception when deleting " + thisGuyStr + ". ErrorCode = " + errorCode + ", errorText = " + errText + ", details = " + errDetail); } } @@ -880,7 +884,8 @@ public class ModelBasedProcessing { // We'd expect to get a "node not found" here sometimes depending on the order that // the model has us finding / deleting nodes. // Ignore the exception - but log it so we can see what happened. - LOGGER.warn("Exception when deleting " + thisGuyStr + e.getMessage() + LogFormatTools.getStackTop(e)); + AAIException aaiException = new AAIException("AAI_6154", thisGuyStr + ". msg = " + e.getMessage()); + ErrorLogHelper.logException(aaiException); } // We can't depend on a thrown exception to tell us if a node was deleted since it may 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 a8f0153..d0e881d 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 @@ -19,24 +19,10 @@ */ package org.onap.aai.dbgraphmap; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriBuilderException; -import javax.xml.bind.JAXBException; - +import com.google.common.base.CaseFormat; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import edu.emory.mathcs.backport.java.util.Collections; import org.apache.commons.lang3.StringUtils; import org.apache.tinkerpop.gremlin.process.traversal.P; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; @@ -52,42 +38,42 @@ import org.onap.aai.db.props.AAIProperties; import org.onap.aai.dbgen.PropertyLimitDesc; import org.onap.aai.dbgraphgen.ModelBasedProcessing; import org.onap.aai.dbgraphgen.ResultSet; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.EdgeRule; import org.onap.aai.edges.EdgeRuleQuery; import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.extensions.AAIExtensionMap; -import org.onap.aai.introspection.Introspector; -import org.onap.aai.introspection.Loader; -import org.onap.aai.introspection.LoaderFactory; -import org.onap.aai.introspection.ModelType; -import org.onap.aai.introspection.MoxyLoader; +import org.onap.aai.introspection.*; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; +import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.parsers.relationship.RelationshipToURI; import org.onap.aai.query.builder.QueryBuilder; +import org.onap.aai.rest.util.AAIExtensionMap; import org.onap.aai.schema.enums.ObjectMetadata; import org.onap.aai.schema.enums.PropertyMetadata; import org.onap.aai.serialization.db.DBSerializer; -import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; 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.GenericQueryBuilder; import org.onap.aai.util.NodesQueryBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import com.google.common.base.CaseFormat; - -import edu.emory.mathcs.backport.java.util.Collections; - -import com.google.common.collect.ArrayListMultimap; -import com.google.common.collect.Multimap; -import org.onap.aai.util.GenericQueryBuilder; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilderException; +import javax.xml.bind.JAXBException; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** @@ -97,7 +83,7 @@ import org.onap.aai.util.GenericQueryBuilder; */ public class SearchGraph { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchGraph.class); + private static final Logger LOGGER = LoggerFactory.getLogger(SearchGraph.class); private LoaderFactory loaderFactory; @@ -145,11 +131,10 @@ public class SearchGraph { // 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()); + genericQueryBuilder.getLoader().introspectorFromName(genericQueryBuilder.getStartNodeType()); // Build a hash with keys to uniquely identify the start Node - String keyName = null; - String keyValue = null; + String keyName; + String keyValue; QueryBuilder builder = genericQueryBuilder.getDbEngine().getQueryBuilder() .getVerticesByIndexedProperty(AAIProperties.NODE_TYPE, "service-instance"); @@ -185,7 +170,7 @@ public class SearchGraph { Vertex startNode = results.get(0); Collection<Vertex> ver = new HashSet<>(); - List<Vertex> queryResults = new ArrayList<>(); + List<Vertex> queryResults; GraphTraversalSource traversalSource = genericQueryBuilder.getDbEngine().asAdmin().getReadOnlyTraversalSource(); GraphTraversal<Vertex, Vertex> traversal; @@ -204,7 +189,8 @@ public class SearchGraph { if (queryResults.isEmpty()) { - LOGGER.warn("No nodes found - apipe was null/empty"); + AAIException aaiException = new AAIException("AAI_6114", "No nodes found - apipe was null/empty"); + ErrorLogHelper.logException(aaiException); } else { Introspector searchResults = createSearchResults(genericQueryBuilder.getLoader(), @@ -218,7 +204,7 @@ public class SearchGraph { result = searchResults.marshal(properties); response = Response.ok().entity(result).build(); - LOGGER.debug(ver.size() + " node(s) traversed, " + queryResults.size() + " found"); + LOGGER.debug("{} node(s) traversed, {} found", ver.size(), queryResults.size()); } success = true; } catch (AAIException e) { @@ -286,8 +272,7 @@ public class SearchGraph { Introspector target; - if (StringUtils.isBlank(nodesQuery.getTargetNodeType()) - || StringUtils.isBlank(nodesQuery.getTargetNodeType())) { + if (StringUtils.isBlank(nodesQuery.getTargetNodeType())) { throw new AAIException("AAI_6120", "null or empty target-node-type passed to the node query"); } @@ -300,13 +285,11 @@ public class SearchGraph { 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"); + LOGGER.debug("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(":"); @@ -322,13 +305,12 @@ public class SearchGraph { String value = "?"; if (pieces.length == 3) { value = pieces[2]; - } else if (pieces.length > 3) { + } else { // 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) { @@ -337,19 +319,16 @@ public class SearchGraph { String value = "?"; if (pieces.length == 3) { value = pieces[2]; - } else if (pieces.length > 3) { + } else { // 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 + "]"); @@ -400,7 +379,7 @@ public class SearchGraph { if (filterType.equals(DOES_NOT_EXIST)) { traversal.where(__.not(edgeSearch)); - } else if (filterType.equals(EXISTS)) { + } else { traversal.where(edgeSearch); } } @@ -521,7 +500,7 @@ public class SearchGraph { * @throws AAIException the AAI exception */ public Response runNamedQuery(String fromAppId, String transId, String queryParameters, - DBConnectionType connectionType, AAIExtensionMap aaiExtMap) throws JAXBException, AAIException { + AAIExtensionMap aaiExtMap) throws AAIException { Introspector inventoryItems; boolean success = true; @@ -531,7 +510,7 @@ public class SearchGraph { MoxyLoader loader = (MoxyLoader) loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); DynamicJAXBContext jaxbContext = loader.getJAXBContext(); - dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, connectionType, loader); + dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer serializer = new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); @@ -552,7 +531,7 @@ public class SearchGraph { if (modelAndNamedQuerySearch == null) { throw new AAIException("AAI_5105"); } - HashMap<String, Object> namedQueryLookupHash = new HashMap<String, Object>(); + Map<String, Object> namedQueryLookupHash = new HashMap<>(); DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); String namedQueryUuid = null; @@ -590,12 +569,12 @@ public class SearchGraph { List<Map<String, Object>> startNodeFilterHash = new ArrayList<>(); - mapInstanceFilters((DynamicEntity) modelAndNamedQuerySearch.get("instanceFilters"), startNodeFilterHash, + mapInstanceFilters(modelAndNamedQuerySearch.get("instanceFilters"), startNodeFilterHash, jaxbContext); Map<String, Object> secondaryFilterHash = new HashMap<>(); - mapSecondaryFilters((DynamicEntity) modelAndNamedQuerySearch.get("secondaryFilts"), secondaryFilterHash, + mapSecondaryFilters(modelAndNamedQuerySearch.get("secondaryFilts"), secondaryFilterHash, jaxbContext); List<ResultSet> resultSet = processor.queryByNamedQuery(transId, fromAppId, namedQueryUuid, @@ -641,8 +620,8 @@ public class SearchGraph { * @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 { + boolean isDelete, AAIExtensionMap aaiExtMap) + throws AAIException, DynamicException { Response response; boolean success = true; TransactionalGraphEngine dbEngine = null; @@ -651,7 +630,7 @@ public class SearchGraph { MoxyLoader loader = (MoxyLoader) loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); DynamicJAXBContext jaxbContext = loader.getJAXBContext(); - dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, connectionType, loader); + dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer serializer = new DBSerializer(schemaVersions.getDefaultVersion(), dbEngine, ModelType.MOXY, fromAppId); ModelBasedProcessing processor = new ModelBasedProcessing(loader, dbEngine, serializer); @@ -674,12 +653,10 @@ public class SearchGraph { throw new AAIException("AAI_5105"); } - Map<String, Object> modelQueryLookupHash = new HashMap<>(); - String modelVersionId = null; String modelName = null; String modelInvariantId = null; - String modelVersion = null; + String modelVersion; String topNodeType = null; if (modelAndNamedQuerySearch.isSet("topNodeType")) { @@ -698,7 +675,7 @@ public class SearchGraph { DynamicEntity qp = modelAndNamedQuerySearch.get("queryParameters"); if (qp.isSet("model")) { - DynamicEntity model = (DynamicEntity) qp.get("model"); + DynamicEntity model = qp.get("model"); // on an old-style model object, the following 4 attrs were all present if (model.isSet("modelNameVersionId")) { @@ -723,7 +700,7 @@ public class SearchGraph { 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"); + DynamicEntity modelVers = 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 @@ -752,8 +729,7 @@ public class SearchGraph { 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); + unpackResultSet(resultSet, dbEngine, loader, serializer); ResultSet rs = resultSet.get(0); diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java index 146f847..ccf89fc 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/post/AAIResponseFilterPriority.java @@ -22,7 +22,7 @@ package org.onap.aai.interceptors.post; /** * Response Filter order is done reverse sorted * so in the following case the first response filter would be - * HEADER_MANIPULATION, RESPONSE_TRANS_LOGGING, RESET_LOGGING_CONTEXT, + * HEADER_MANIPULATION, RESPONSE_TRANS_LOGGING, * and INVALID_RESPONSE_STATUS */ public final class AAIResponseFilterPriority { @@ -31,8 +31,6 @@ public final class AAIResponseFilterPriority { public static final int INVALID_RESPONSE_STATUS = 1000; - public static final int RESET_LOGGING_CONTEXT = 2000; - public static final int RESPONSE_TRANS_LOGGING = 3000; public static final int HEADER_MANIPULATION = 4000; diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResetLoggingContext.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResetLoggingContext.java deleted file mode 100644 index baf28ad..0000000 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResetLoggingContext.java +++ /dev/null @@ -1,98 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.interceptors.post; - -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import org.onap.aai.interceptors.AAIContainerFilter; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.LoggingContext.StatusCode; -import org.springframework.beans.factory.annotation.Autowired; - -import javax.annotation.Priority; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerResponseContext; -import javax.ws.rs.container.ContainerResponseFilter; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.Response.StatusType; -import java.io.IOException; - -@Priority(AAIResponseFilterPriority.RESET_LOGGING_CONTEXT) -public class ResetLoggingContext extends AAIContainerFilter implements ContainerResponseFilter { - - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ResetLoggingContext.class); - - @Autowired - private HttpServletRequest httpServletRequest; - - @Override - public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) - throws IOException { - - this.cleanLoggingContext(responseContext); - - } - - private void cleanLoggingContext(ContainerResponseContext responseContext) { - //String url = httpServletRequest.getRequestURL().toString(); - boolean success = true; - String uri = httpServletRequest.getRequestURI(); - String queryString = httpServletRequest.getQueryString(); - - if(queryString != null && !queryString.isEmpty()){ - uri = uri + "?" + queryString; - } - // For now, we use the the HTTP status code, - // This may change, once the requirements for response codes are defined - - int httpStatusCode = responseContext.getStatus(); - if ( httpStatusCode < 100 || httpStatusCode > 599 ) { - httpStatusCode = Status.INTERNAL_SERVER_ERROR.getStatusCode(); - } - LoggingContext.responseCode(Integer.toString(httpStatusCode)); - - StatusType sType = responseContext.getStatusInfo(); - if ( sType != null ) { - Status.Family sFamily = sType.getFamily(); - if ( ! ( Status.Family.SUCCESSFUL.equals(sFamily) || - ( Status.NOT_FOUND.equals(Status.fromStatusCode(httpStatusCode)) ) ) ) { - success = false; - } - } - else { - if ( (httpStatusCode < 200 || httpStatusCode > 299) && ( ! ( Status.NOT_FOUND.equals(Status.fromStatusCode(httpStatusCode) ) ) ) ) { - success = false; - } - } - if (success) { - LoggingContext.statusCode(StatusCode.COMPLETE); - LOGGER.info(uri + " call succeeded"); - } - else { - LoggingContext.statusCode(StatusCode.ERROR); - LOGGER.error(uri + " call failed with responseCode=" + httpStatusCode); - } - LoggingContext.clear(); - - - } - -} diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java index 547a7c8..51fe871 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/post/ResponseTransactionLogging.java @@ -19,14 +19,14 @@ */ package org.onap.aai.interceptors.post; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import com.google.gson.JsonObject; import org.onap.aai.exceptions.AAIException; import org.onap.aai.interceptors.AAIContainerFilter; import org.onap.aai.interceptors.AAIHeaderProperties; import org.onap.aai.logging.ErrorLogHelper; import org.onap.aai.util.AAIConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.Priority; @@ -34,14 +34,21 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.core.PathSegment; import java.io.IOException; -import java.util.Objects; -import java.util.Optional; +import java.util.*; @Priority(AAIResponseFilterPriority.RESPONSE_TRANS_LOGGING) public class ResponseTransactionLogging extends AAIContainerFilter implements ContainerResponseFilter { - private static final EELFLogger TRANSACTION_LOGGER = EELFManager.getInstance().getLogger(ResponseTransactionLogging.class); + private static final Logger TRANSACTION_LOGGER = LoggerFactory.getLogger(ResponseTransactionLogging.class); + + private final static String QUERY_API_PATH_SEGMENT = "query"; + private final static String NODES_QUERY_API_PATH_SEGMENT = "nodes-query"; + private final static String GENERIC_QUERY_API_PATH_SEGMENT = "generic-query"; + private final static String DSL_API_PATH_SEGMENT = "dsl"; + private final static String RECENTS_API_PATH_SEGMENT = "recents"; + private final static Set<String> READ_ONLY_QUERIES = getReadOnlyQueries(); @Autowired private HttpServletResponse httpServletResponse; @@ -57,12 +64,13 @@ public class ResponseTransactionLogging extends AAIContainerFilter implements Co private void transLogging(ContainerRequestContext requestContext, ContainerResponseContext responseContext) { String logValue; - String getValue; + String isGetTransactionResponseLoggingEnabled; String postValue; - + try { + logValue = AAIConfig.get("aai.transaction.logging"); - getValue = AAIConfig.get("aai.transaction.logging.get"); + isGetTransactionResponseLoggingEnabled = AAIConfig.get("aai.transaction.logging.get"); postValue = AAIConfig.get("aai.transaction.logging.post"); } catch (AAIException e) { return; @@ -81,7 +89,6 @@ public class ResponseTransactionLogging extends AAIContainerFilter implements Co String response = this.getResponseString(responseContext); if (!Boolean.parseBoolean(logValue)) { - } else if (!Boolean.parseBoolean(getValue) && "GET".equals(httpMethod)) { } else if (!Boolean.parseBoolean(postValue) && "POST".equals(httpMethod)) { } else { @@ -94,12 +101,33 @@ public class ResponseTransactionLogging extends AAIContainerFilter implements Co logEntry.addProperty("resourceId", fullUri); logEntry.addProperty("resourceType", httpMethod); logEntry.addProperty("rqstBuf", Objects.toString(request, "")); - logEntry.addProperty("respBuf", Objects.toString(response, "")); - - try { - TRANSACTION_LOGGER.debug(logEntry.toString()); - } catch (Exception e) { - ErrorLogHelper.logError("AAI_4000", "Exception writing transaction log."); + + boolean recordResponse = true; + if (!Boolean.parseBoolean(isGetTransactionResponseLoggingEnabled) && "GET".equals(httpMethod)) { + recordResponse = false; + } + else { + /** + * Parse the uri path and see if it is a read-only query + * If it is, do not record the response in the logs + */ + + List<PathSegment> pathSegmentList = requestContext.getUriInfo().getPathSegments(); + for (PathSegment queryType : pathSegmentList) { + if (READ_ONLY_QUERIES.contains(queryType.toString())) { + recordResponse = false; + } + } + + if (recordResponse) { + logEntry.addProperty("respBuf", Objects.toString(response, "")); + } + + try { + TRANSACTION_LOGGER.debug(logEntry.toString()); + } catch (Exception e) { + ErrorLogHelper.logError("AAI_4000", "Exception writing transaction log."); + } } } @@ -120,4 +148,14 @@ public class ResponseTransactionLogging extends AAIContainerFilter implements Co return response.toString(); } + private static Set<String> getReadOnlyQueries() { + Set<String> readOnlyQueries = new HashSet<String>(); + readOnlyQueries.add(NODES_QUERY_API_PATH_SEGMENT); + readOnlyQueries.add(GENERIC_QUERY_API_PATH_SEGMENT); + readOnlyQueries.add(RECENTS_API_PATH_SEGMENT); + readOnlyQueries.add(QUERY_API_PATH_SEGMENT); + readOnlyQueries.add(DSL_API_PATH_SEGMENT); + return readOnlyQueries; + } + } diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java index c3d9d3b..4af96c5 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/AAIRequestFilterPriority.java @@ -27,8 +27,6 @@ public final class AAIRequestFilterPriority { public static final int HEADER_VALIDATION = 2000; - public static final int SET_LOGGING_CONTEXT = 3000; - public static final int HTTP_HEADER = 4000; public static final int LATEST = 4250; diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java index d6b6080..d70cb01 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/HeaderValidation.java @@ -23,6 +23,8 @@ import org.onap.aai.exceptions.AAIException; import org.onap.aai.interceptors.AAIContainerFilter; import org.onap.aai.interceptors.AAIHeaderProperties; import org.onap.aai.logging.ErrorLogHelper; +import org.onap.logging.filter.base.Constants; +import org.onap.logging.ref.slf4j.ONAPLogConstants; import javax.annotation.Priority; import javax.ws.rs.container.ContainerRequestContext; @@ -34,7 +36,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.UUID; @PreMatching @Priority(AAIRequestFilterPriority.HEADER_VALIDATION) @@ -44,36 +45,28 @@ public class HeaderValidation extends AAIContainerFilter implements ContainerReq public void filter(ContainerRequestContext requestContext) throws IOException { Optional<Response> oResp; - - String transId = requestContext.getHeaderString(AAIHeaderProperties.TRANSACTION_ID); - String fromAppId = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); List<MediaType> acceptHeaderValues = requestContext.getAcceptableMediaTypes(); + String fromAppId = getPartnerName(requestContext); oResp = this.validateHeaderValuePresence(fromAppId, "AAI_4009", acceptHeaderValues); if (oResp.isPresent()) { requestContext.abortWith(oResp.get()); return; } + String transId = getRequestId(requestContext); oResp = this.validateHeaderValuePresence(transId, "AAI_4010", acceptHeaderValues); if (oResp.isPresent()) { requestContext.abortWith(oResp.get()); return; } - - if (!this.isValidUUID(transId)) { - transId = UUID.randomUUID().toString(); - requestContext.getHeaders().get(AAIHeaderProperties.TRANSACTION_ID).clear(); - requestContext.getHeaders().add(AAIHeaderProperties.TRANSACTION_ID, transId); - } - } private Optional<Response> validateHeaderValuePresence(String value, String errorCode, List<MediaType> acceptHeaderValues) { Response response = null; AAIException aaie; - if (value == null) { + if (value == null || value.isEmpty()) { aaie = new AAIException(errorCode); return Optional.of(Response.status(aaie.getErrorObject().getHTTPResponseCode()) .entity(ErrorLogHelper.getRESTAPIErrorResponse(acceptHeaderValues, aaie, new ArrayList<>())) @@ -82,5 +75,52 @@ public class HeaderValidation extends AAIContainerFilter implements ContainerReq return Optional.ofNullable(response); } + public String getRequestId(ContainerRequestContext requestContext) { + String requestId = requestContext.getHeaderString(ONAPLogConstants.Headers.REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = requestContext.getHeaderString(Constants.HttpHeaders.HEADER_REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = requestContext.getHeaderString(Constants.HttpHeaders.TRANSACTION_ID); + if (requestId == null || requestId.isEmpty()) { + requestId = requestContext.getHeaderString(Constants.HttpHeaders.ECOMP_REQUEST_ID); + if (requestId == null || requestId.isEmpty()) { + return requestId; + } + } + } + } + if (requestContext.getHeaders().get(ONAPLogConstants.Headers.REQUEST_ID) != null) { + requestContext.getHeaders().get(ONAPLogConstants.Headers.REQUEST_ID).clear(); + } + if (requestContext.getHeaders().get(Constants.HttpHeaders.TRANSACTION_ID) != null) { + requestContext.getHeaders().get(Constants.HttpHeaders.TRANSACTION_ID).clear(); + } + if (requestContext.getHeaders().get(Constants.HttpHeaders.HEADER_REQUEST_ID) != null) { + requestContext.getHeaders().get(Constants.HttpHeaders.HEADER_REQUEST_ID).clear(); + } + if (requestContext.getHeaders().get(Constants.HttpHeaders.ECOMP_REQUEST_ID) != null) { + requestContext.getHeaders().get(Constants.HttpHeaders.ECOMP_REQUEST_ID).clear(); + } + requestContext.getHeaders().add(Constants.HttpHeaders.TRANSACTION_ID, requestId); + + return requestId; + } + public String getPartnerName(ContainerRequestContext requestContext) { + String partnerName = requestContext.getHeaderString(ONAPLogConstants.Headers.PARTNER_NAME); + if (partnerName == null || (partnerName.isEmpty())) { + partnerName = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); + if (partnerName == null || (partnerName.isEmpty())) { + return partnerName; + } + } + if (requestContext.getHeaders().get(ONAPLogConstants.Headers.PARTNER_NAME) != null) { + requestContext.getHeaders().get(ONAPLogConstants.Headers.PARTNER_NAME).clear(); + } + if (requestContext.getHeaders().get(AAIHeaderProperties.FROM_APP_ID) != null) { + requestContext.getHeaders().get(AAIHeaderProperties.FROM_APP_ID).clear(); + } + requestContext.getHeaders().add(AAIHeaderProperties.FROM_APP_ID, partnerName); + return partnerName; + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java index 6c86f19..03cac8d 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/RequestTransactionLogging.java @@ -37,6 +37,8 @@ import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.PreMatching; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -58,6 +60,8 @@ public class RequestTransactionLogging extends AAIContainerFilter implements Con private static final String CONTENT_TYPE = "Content-Type"; private static final String ACCEPT = "Accept"; private static final String TEXT_PLAIN = "text/plain"; + private static final String WILDCARD = "*/*"; + private static final String APPLICATION_JSON = "application/json"; @Override public void filter(ContainerRequestContext requestContext) throws IOException { @@ -83,8 +87,18 @@ public class RequestTransactionLogging extends AAIContainerFilter implements Con requestContext.getHeaders().putSingle(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); } - if(StringUtils.isEmpty(acceptType) || acceptType.contains(TEXT_PLAIN)){ - requestContext.getHeaders().putSingle(ACCEPT, DEFAULT_RESPONSE_TYPE); + if(WILDCARD.equals(acceptType) || StringUtils.isEmpty(acceptType) || acceptType.contains(TEXT_PLAIN)){ + UriInfo uriInfo = requestContext.getUriInfo(); + if(uriInfo != null){ + String path = uriInfo.getPath(); + if(path.endsWith("/dsl") || path.endsWith("/query") || path.contains("/recents/")){ + requestContext.getHeaders().putSingle(ACCEPT, APPLICATION_JSON); + } else { + requestContext.getHeaders().putSingle(ACCEPT, DEFAULT_RESPONSE_TYPE); + } + } else { + requestContext.getHeaders().putSingle(ACCEPT, DEFAULT_RESPONSE_TYPE); + } } } diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java deleted file mode 100644 index 4b0f18a..0000000 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/SetLoggingContext.java +++ /dev/null @@ -1,69 +0,0 @@ -/** - * ============LICENSE_START======================================================= - * org.onap.aai - * ================================================================================ - * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ -package org.onap.aai.interceptors.pre; - -import org.onap.aai.interceptors.AAIContainerFilter; -import org.onap.aai.interceptors.AAIHeaderProperties; -import org.onap.aai.logging.LoggingContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.env.Environment; - -import javax.annotation.Priority; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.container.ContainerRequestContext; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.PreMatching; -import java.io.IOException; - -@PreMatching -@Priority(AAIRequestFilterPriority.SET_LOGGING_CONTEXT) -public class SetLoggingContext extends AAIContainerFilter implements ContainerRequestFilter { - - @Autowired - private Environment environment; - - @Autowired - private HttpServletRequest httpServletRequest; - - @Override - public void filter(ContainerRequestContext requestContext) throws IOException { - - String uri = httpServletRequest.getRequestURI(); - String queryString = httpServletRequest.getQueryString(); - - if(queryString != null && !queryString.isEmpty()){ - uri = uri + "?" + queryString; - } - - String httpMethod = requestContext.getMethod(); - String transId = requestContext.getHeaderString(AAIHeaderProperties.TRANSACTION_ID); - String fromAppId = requestContext.getHeaderString(AAIHeaderProperties.FROM_APP_ID); - - LoggingContext.init(); - LoggingContext.requestId(transId); - LoggingContext.partnerName(fromAppId); - LoggingContext.targetEntity(environment.getProperty("spring.application.name")); - LoggingContext.component(fromAppId); - LoggingContext.serviceName(httpMethod + " " + uri); - LoggingContext.targetServiceName(httpMethod + " " + uri); - LoggingContext.statusCode(LoggingContext.StatusCode.COMPLETE); - } - -} diff --git a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java index bc03082..58c7be6 100644 --- a/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java +++ b/aai-traversal/src/main/java/org/onap/aai/interceptors/pre/TwoWaySslAuthorization.java @@ -19,7 +19,7 @@ */ package org.onap.aai.interceptors.pre; -import org.onap.aai.auth.AAIAuthCore; +import org.onap.aai.aaf.auth.AAIAuthCore; import org.onap.aai.exceptions.AAIException; import org.onap.aai.interceptors.AAIContainerFilter; import org.onap.aai.interceptors.AAIHeaderProperties; diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java index dcf8418..d075f70 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2Gremlin.java @@ -19,23 +19,7 @@ */ package org.onap.aai.rest; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.ws.rs.Consumes; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - import org.onap.aai.config.SpringContextAware; -import org.onap.aai.dbmap.DBConnectionType; -import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.rest.search.CustomQueryConfigDTO; @@ -50,6 +34,15 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestBody; +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.*; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + @Path("/cq2gremlin") public class CQ2Gremlin extends RESTAPI { @@ -86,8 +79,6 @@ public class CQ2Gremlin extends RESTAPI { protected Response processGremlinQuery(CustomQueryConfigDTO content, UriInfo info, HttpHeaders headers) { try{ - String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); LinkedHashMap <String, Object> params; CustomQueryDTO queryDTO = content.getQueryDTO(); String query = queryDTO.getQuery(); @@ -108,8 +99,7 @@ public class CQ2Gremlin extends RESTAPI { } SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class); - DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime); - traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); traversalUriHttpEntry.setPaginationParameters("-1", "-1"); TransactionalGraphEngine dbEngine = traversalUriHttpEntry.getDbEngine(); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java index 40538be..e3cfaca 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/CQ2GremlinTest.java @@ -20,26 +20,8 @@ package org.onap.aai.rest; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; - -import javax.ws.rs.Consumes; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.UriInfo; - +import com.beust.jcommander.internal.Lists; +import com.beust.jcommander.internal.Maps; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Graph; @@ -47,7 +29,6 @@ import org.apache.tinkerpop.gremlin.structure.T; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph; import org.onap.aai.config.SpringContextAware; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.LoaderFactory; @@ -61,21 +42,27 @@ import org.onap.aai.serialization.db.EdgeSerializer; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RequestBody; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import com.beust.jcommander.internal.Lists; -import com.beust.jcommander.internal.Maps; +import javax.ws.rs.Consumes; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.*; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; @Path("/cq2gremlintest") public class CQ2GremlinTest extends RESTAPI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(CQ2GremlinTest.class); + private static final Logger LOGGER = LoggerFactory.getLogger(CQ2GremlinTest.class); private HttpEntry traversalUriHttpEntry; @@ -110,8 +97,7 @@ public class CQ2GremlinTest extends RESTAPI { String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); String realTime = headers.getRequestHeaders().getFirst("Real-Time"); SchemaVersions schemaVersions = SpringContextAware.getBean(SchemaVersions.class); - DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime); - traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion(), type); + traversalUriHttpEntry.setHttpEntryProperties(schemaVersions.getDefaultVersion()); traversalUriHttpEntry.setPaginationParameters("-1", "-1"); return processC2UnitTest(content); } @@ -123,12 +109,12 @@ public class CQ2GremlinTest extends RESTAPI { gts = graph.traversal(); List<Vertex> expectedVertices = createGraph(content, graph); GremlinGroovyShell shell = new GremlinGroovyShell(); - loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, new SchemaVersion("v16")); + loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, new SchemaVersion("v19")); LinkedHashMap <String, Object> params = new LinkedHashMap<>(); //Adding parameters - content.getQueryRequiredProperties().forEach((K, V) -> {params.put(K, V);}); - content.getQueryOptionalProperties().forEach((K, V) -> {params.put(K, V);}); + content.getQueryRequiredProperties().forEach(params::put); + content.getQueryOptionalProperties().forEach(params::put); String query = new GroovyQueryBuilder().executeTraversal(dbEngine, content.getStoredQuery(), params); query = "g" + query; @@ -166,17 +152,17 @@ public class CQ2GremlinTest extends RESTAPI { private List<Vertex> createGraph(CustomQueryTestDTO content, Graph graph) { Map<String, Vertex> verticesMap = Maps.newLinkedHashMap(); //Creating all the Vertices - content.getVerticesDtos().stream().forEach(vertex -> { + content.getVerticesDtos().forEach(vertex -> { StringBuilder vertexIdentifier = new StringBuilder(); List<String> keyValues = Lists.newArrayList(); keyValues.add(T.id.toString()); keyValues.add(String.format("%02d", verticesMap.size() * 10)); AtomicInteger index = new AtomicInteger(0); - vertex.forEach((K, V) -> { + vertex.forEach((k, v) -> { if(index.get() == 1) - vertexIdentifier.append(V); - keyValues.add(K); - keyValues.add(V); + vertexIdentifier.append(k); + keyValues.add(k); + keyValues.add(v); index.incrementAndGet(); }); Vertex graphVertex = graph.addVertex(keyValues.toArray()); @@ -186,7 +172,7 @@ public class CQ2GremlinTest extends RESTAPI { GraphTraversalSource g = graph.traversal(); //Creating all the Edges - content.getEdgesDtos().stream().forEach(edge -> { + content.getEdgesDtos().forEach(edge -> { String fromId = edge.get("from-id"); String toId = edge.get("to-id"); boolean treeEdgeIdentifier = !"NONE".equalsIgnoreCase(edge.get("contains-other-v")); @@ -207,9 +193,7 @@ public class CQ2GremlinTest extends RESTAPI { List<Vertex> expectedVertices = Lists.newArrayList(); - content.getExpectedResultsDtos().getIds().stream().forEach(vertexId -> { - expectedVertices.add(verticesMap.get(vertexId)); - }); + content.getExpectedResultsDtos().getIds().forEach(vertexId -> expectedVertices.add(verticesMap.get(vertexId))); return expectedVertices; } @@ -218,8 +202,8 @@ public class CQ2GremlinTest extends RESTAPI { if(!startNodeVertex.isPresent()){ throw new IllegalArgumentException("start-node was not specified"); } - startNodeVertex.get().forEach((K, V) -> { - g.has(K, V); + startNodeVertex.get().forEach((k, v) -> { + g.has(k, v); }); } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java index 2d09636..6cb6565 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/DslConsumer.java @@ -19,24 +19,20 @@ */ package org.onap.aai.rest; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.onap.aai.concurrent.AaiCallable; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.ModelType; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.StopWatch; import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.rest.dsl.DslQueryProcessor; +import org.onap.aai.rest.enums.QueryVersion; import org.onap.aai.rest.search.GenericQueryProcessor; import org.onap.aai.rest.search.GremlinServerSingleton; import org.onap.aai.rest.search.QueryProcessorType; import org.onap.aai.restcore.HttpMethod; -import org.onap.aai.restcore.RESTAPI; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.engines.TransactionalGraphEngine; import org.onap.aai.serialization.queryformats.Format; @@ -45,27 +41,29 @@ import org.onap.aai.serialization.queryformats.Formatter; import org.onap.aai.serialization.queryformats.SubGraphStyle; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; +import org.onap.aai.transforms.XmlFormatTransformer; import org.onap.aai.util.AAIConfig; import org.onap.aai.util.TraversalConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import javax.servlet.http.HttpServletRequest; import javax.ws.rs.*; import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.Map; +import java.util.Optional; @Path("{version: v[1-9][0-9]*|latest}/dsl") -public class DslConsumer extends RESTAPI { +public class DslConsumer extends TraversalConsumer { private HttpEntry traversalUriHttpEntry; private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; - private static final String TARGET_ENTITY = "DB"; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslConsumer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DslConsumer.class); private DslQueryProcessor dslQueryProcessor; @@ -74,53 +72,74 @@ public class DslConsumer extends RESTAPI { private String basePath; private GremlinServerSingleton gremlinServerSingleton; + private final QueryVersion DEFAULT_VERSION = QueryVersion.V1; + private QueryVersion dslApiVersion = DEFAULT_VERSION; + + private XmlFormatTransformer xmlFormatTransformer; @Autowired public DslConsumer(HttpEntry traversalUriHttpEntry, DslQueryProcessor dslQueryProcessor, - SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton, - @Value("${schema.uri.base.path}") String basePath) { + SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton, + XmlFormatTransformer xmlFormatTransformer, + @Value("${schema.uri.base.path}") String basePath) { this.traversalUriHttpEntry = traversalUriHttpEntry; this.dslQueryProcessor = dslQueryProcessor; this.schemaVersions = schemaVersions; this.gremlinServerSingleton = gremlinServerSingleton; + this.xmlFormatTransformer = xmlFormatTransformer; this.basePath = basePath; } @PUT @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response executeQuery(String content, @PathParam("version") String versionParam, - @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat, - @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, - @Context UriInfo info, @Context HttpServletRequest req, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response executeQuery(String content, + @PathParam("version") String versionParam, + @DefaultValue("graphson") @QueryParam("format") String queryFormat, + @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, + @DefaultValue("all") @QueryParam("validate") String validate, + @Context HttpHeaders headers, + @Context UriInfo info, + @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, + @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { return runner(TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_ENABLED, - TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_APP, TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_LIMIT, - headers, info, HttpMethod.PUT, new AaiCallable<Response>() { + TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_APP, + TraversalConstants.AAI_TRAVERSAL_DSL_TIMEOUT_LIMIT, + headers, + info, + HttpMethod.PUT, + new AaiCallable() { @Override - public Response process() { - return processExecuteQuery(content, versionParam, uri, queryFormat, subgraph, headers, info, - req, resultIndex, resultSize); + public Response process() throws Exception { + return (processExecuteQuery(content, versionParam, queryFormat, subgraph, validate, headers, info, + resultIndex, resultSize)); } - }); + } + ); } - public Response processExecuteQuery(String content, @PathParam("version") String versionParam, - @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat, - @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, - @Context UriInfo info, @Context HttpServletRequest req, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { + public Response processExecuteQuery(String content, String versionParam, String queryFormat, String subgraph, + String validate, HttpHeaders headers, UriInfo info, String resultIndex, + String resultSize) { - String methodName = "executeDslQuery"; String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); String dslOverride = headers.getRequestHeaders().getFirst("X-DslOverride"); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); + + Optional<String> dslApiVersionHeader = Optional.ofNullable(headers.getRequestHeaders().getFirst("X-DslApiVersion")); + if (dslApiVersionHeader.isPresent()) { + try { + dslApiVersion = QueryVersion.valueOf(dslApiVersionHeader.get()); + } catch (IllegalArgumentException e) { + LOGGER.debug("Defaulting DSL Api Version to "+DEFAULT_VERSION); + } + } + Response response; SchemaVersion version = new SchemaVersion(versionParam); TransactionalGraphEngine dbEngine = null; try { - LoggingContext.save(); - DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime); - traversalUriHttpEntry.setHttpEntryProperties(version, type); + traversalUriHttpEntry.setHttpEntryProperties(version); traversalUriHttpEntry.setPaginationParameters(resultIndex, resultSize); dbEngine = traversalUriHttpEntry.getDbEngine(); JsonObject input = new JsonParser().parse(content).getAsJsonObject(); @@ -130,48 +149,83 @@ public class DslConsumer extends RESTAPI { dsl = dslElement.getAsString(); } - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - LoggingContext.startTime(); - StopWatch.conditionalStart(); boolean isDslOverride = dslOverride != null && !AAIConfig.get(TraversalConstants.DSL_OVERRIDE).equals("false") && dslOverride.equals(AAIConfig.get(TraversalConstants.DSL_OVERRIDE)); - if(isDslOverride) - dslQueryProcessor.setValidationFlag(false); - + if(isDslOverride) { + dslQueryProcessor.setStartNodeValidationFlag(false); + } + + dslQueryProcessor.setValidationRules(validate); + + Format format = Format.getFormat(queryFormat); + + if(isAggregate(format)){ + dslQueryProcessor.setAggregate(true); + } + + if(isHistory(format)){ + validateHistoryParams(format, info.getQueryParameters()); + } + + GraphTraversalSource traversalSource = getTraversalSource(dbEngine, format, info); + GenericQueryProcessor processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .queryFrom(dsl, "dsl").queryProcessor(dslQueryProcessor).processWith(processorType).create(); - - String result = ""; + .queryFrom(dsl, "dsl").queryProcessor(dslQueryProcessor).version(dslApiVersion).processWith(processorType) + .format(format).uriParams(info.getQueryParameters()).traversalSource(isHistory(format), traversalSource).create(); + SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); List<Object> vertTemp = processor.execute(subGraphStyle); - List<Object> vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); + + List <Object> vertices; + if (isAggregate(format)){ + vertices = traversalUriHttpEntry.getPaginatedVertexListForAggregateFormat(vertTemp); + } else { + vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); + } + DBSerializer serializer = new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); - Format format = Format.getFormat(queryFormat); FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath); - - Formatter formater = ff.get(format, info.getQueryParameters()); - result = formater.output(vertices).toString(); - - double msecs = StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long) msecs, TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - LOGGER.info("Completed"); - + MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); + mvm.putAll(info.getQueryParameters()); + if (isHistory(format)) { + mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm))); + mvm.putSingle("endTs", Long.toString(getEndTime(mvm))); + } + Formatter formatter = ff.get(format, mvm); + + final Map<String, List<String>> propertiesMap = processor.getPropertiesMap(); + String result = ""; + if (propertiesMap != null && !propertiesMap.isEmpty()){ + result = formatter.output(vertices, propertiesMap).toString(); + } + else { + result = formatter.output(vertices).toString(); + } + + String acceptType = headers.getHeaderString("Accept"); + + if(acceptType == null){ + acceptType = MediaType.APPLICATION_JSON; + } + + if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ + result = xmlFormatTransformer.transform(result); + } + if(traversalUriHttpEntry.isPaginated()){ response = Response.status(Status.OK) - .type(MediaType.APPLICATION_JSON) + .type(acceptType) .header("total-results", traversalUriHttpEntry.getTotalVertices()) .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) .entity(result) .build(); }else { response = Response.status(Status.OK) - .type(MediaType.APPLICATION_JSON) + .type(acceptType) .entity(result).build(); } @@ -181,8 +235,6 @@ public class DslConsumer extends RESTAPI { AAIException ex = new AAIException("AAI_4000", e); response = consumerExceptionResponseGenerator(headers, info, HttpMethod.PUT, ex); } finally { - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); if (dbEngine != null) { dbEngine.rollback(); } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java index 633bc9c..d91e50d 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/QueryConsumer.java @@ -19,38 +19,16 @@ */ package org.onap.aai.rest; -import java.net.URI; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DefaultValue; -import javax.ws.rs.Encoded; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriInfo; - +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; import org.apache.tinkerpop.gremlin.structure.Vertex; import org.onap.aai.concurrent.AaiCallable; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.ModelType; import org.onap.aai.logging.ErrorLogHelper; + import org.onap.aai.parsers.query.QueryParser; import org.onap.aai.rest.db.HttpEntry; import org.onap.aai.rest.search.CustomQueryConfig; @@ -58,7 +36,6 @@ import org.onap.aai.rest.search.GenericQueryProcessor; import org.onap.aai.rest.search.GremlinServerSingleton; import org.onap.aai.rest.search.QueryProcessorType; import org.onap.aai.restcore.HttpMethod; -import org.onap.aai.restcore.RESTAPI; import org.onap.aai.restcore.util.URITools; import org.onap.aai.serialization.db.DBSerializer; import org.onap.aai.serialization.engines.QueryStyle; @@ -67,33 +44,28 @@ import org.onap.aai.serialization.queryformats.Format; import org.onap.aai.serialization.queryformats.FormatFactory; import org.onap.aai.serialization.queryformats.Formatter; import org.onap.aai.serialization.queryformats.SubGraphStyle; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.StopWatch; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import org.onap.aai.setup.SchemaVersion; import org.onap.aai.setup.SchemaVersions; -import org.onap.aai.util.AAIConstants; +import org.onap.aai.transforms.XmlFormatTransformer; import org.onap.aai.util.TraversalConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; + @Path("{version: v[1-9][0-9]*|latest}/query") -public class QueryConsumer extends RESTAPI { - - /** The introspector factory type. */ - private ModelType introspectorFactoryType = ModelType.MOXY; - +public class QueryConsumer extends TraversalConsumer { + private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; - /** The query style. */ - private QueryStyle queryStyle = QueryStyle.TRAVERSAL; - - private static final String TARGET_ENTITY = "DB"; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(QueryConsumer.class); + + private static final Logger LOGGER = LoggerFactory.getLogger(QueryConsumer.class); private HttpEntry traversalUriHttpEntry; @@ -104,23 +76,29 @@ public class QueryConsumer extends RESTAPI { private GremlinServerSingleton gremlinServerSingleton; + private XmlFormatTransformer xmlFormatTransformer; + @Autowired - public QueryConsumer( - HttpEntry traversalUriHttpEntry, - SchemaVersions schemaVersions, - GremlinServerSingleton gremlinServerSingleton, - @Value("${schema.uri.base.path}") String basePath - ){ + public QueryConsumer(HttpEntry traversalUriHttpEntry, SchemaVersions schemaVersions, + GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer, @Value("${schema.uri.base.path}") String basePath) { this.traversalUriHttpEntry = traversalUriHttpEntry; this.schemaVersions = schemaVersions; this.gremlinServerSingleton = gremlinServerSingleton; this.basePath = basePath; + this.xmlFormatTransformer = xmlFormatTransformer; } @PUT @Consumes({ MediaType.APPLICATION_JSON}) - @Produces({ MediaType.APPLICATION_JSON}) - public Response executeQuery(String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat,@DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize){ + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response executeQuery(String content, + @PathParam("version") String versionParam, + @DefaultValue("graphson") @QueryParam("format") String queryFormat, + @DefaultValue("no_op") @QueryParam("subgraph") String subgraph, + @Context HttpHeaders headers, + @Context UriInfo info, + @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, + @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP, TraversalConstants.AAI_TRAVERSAL_TIMEOUT_LIMIT, @@ -128,34 +106,33 @@ public class QueryConsumer extends RESTAPI { info, HttpMethod.GET, new AaiCallable<Response>() { - @Override - public Response process() { - return processExecuteQuery(content, versionParam, uri, queryFormat, subgraph, headers, info, req, resultIndex, resultSize); - } - } - ); + @Override + public Response process() { + return processExecuteQuery(content, versionParam, queryFormat, subgraph, headers, info, resultIndex, resultSize); + } + }); } - public Response processExecuteQuery(String content, @PathParam("version")String versionParam, @PathParam("uri") @Encoded String uri, @DefaultValue("graphson") @QueryParam("format") String queryFormat,@DefaultValue("no_op") @QueryParam("subgraph") String subgraph, @Context HttpHeaders headers, @Context UriInfo info, @Context HttpServletRequest req, @DefaultValue("-1") @QueryParam("resultIndex") String resultIndex, @DefaultValue("-1") @QueryParam("resultSize") String resultSize) { - String methodName = "executeQuery"; + public Response processExecuteQuery(String content, String versionParam, String queryFormat, String subgraph, + HttpHeaders headers, UriInfo info, String resultIndex, + String resultSize) { + String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); QueryProcessorType processorType = this.processorType; - Response response = null; + Response response; TransactionalGraphEngine dbEngine = null; + try { - LoggingContext.save(); this.checkQueryParams(info.getQueryParameters()); Format format = Format.getFormat(queryFormat); if (queryProcessor != null) { processorType = QueryProcessorType.valueOf(queryProcessor); } SubGraphStyle subGraphStyle = SubGraphStyle.valueOf(subgraph); + JsonParser parser = new JsonParser(); - JsonObject input = parser.parse(content).getAsJsonObject(); - JsonElement startElement = input.get("start"); JsonElement queryElement = input.get("query"); JsonElement gremlinElement = input.get("gremlin"); @@ -164,8 +141,7 @@ public class QueryConsumer extends RESTAPI { String gremlin = ""; SchemaVersion version = new SchemaVersion(versionParam); - DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime); - traversalUriHttpEntry.setHttpEntryProperties(version, type); + traversalUriHttpEntry.setHttpEntryProperties(version); /* * Changes for Pagination */ @@ -196,76 +172,87 @@ public class QueryConsumer extends RESTAPI { List<String> missingRequiredQueryParameters = checkForMissingQueryParameters( customQueryConfig.getQueryRequiredProperties(), URITools.getQueryMap(queryURIObj)); if ( !missingRequiredQueryParameters.isEmpty() ) { - return( createMessageMissingQueryRequiredParameters( missingRequiredQueryParameters, headers, info, req)); + return( createMessageMissingQueryRequiredParameters( missingRequiredQueryParameters, headers)); } List<String> invalidQueryParameters = checkForInvalidQueryParameters( customQueryConfig, URITools.getQueryMap(queryURIObj)); if ( !invalidQueryParameters.isEmpty() ) { - return( createMessageInvalidQueryParameters( invalidQueryParameters, headers, info, req)); + return( createMessageInvalidQueryParameters( invalidQueryParameters, headers)); } } else if ( queryElement != null ) { - return( createMessageInvalidQuerySection( queryURI, headers, info, req)); + return (createMessageInvalidQuerySection(queryURI, headers)); } - - GenericQueryProcessor processor = null; - - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - LoggingContext.startTime(); - StopWatch.conditionalStart(); + GenericQueryProcessor processor; + + if(isHistory(format)){ + validateHistoryParams(format, info.getQueryParameters()); + } + GraphTraversalSource traversalSource = getTraversalSource(dbEngine, format, info); + QueryStyle queryStyle = getQueryStyle(format, traversalUriHttpEntry); if (!startURIs.isEmpty()) { Set<Vertex> vertexSet = new LinkedHashSet<>(); QueryParser uriQuery; List<Vertex> vertices; for (URI startUri : startURIs) { - uriQuery = dbEngine.getQueryBuilder().createQueryFromURI(startUri, URITools.getQueryMap(startUri)); + uriQuery = dbEngine.getQueryBuilder(queryStyle, traversalSource).createQueryFromURI(startUri, URITools.getQueryMap(startUri)); vertices = uriQuery.getQueryBuilder().toList(); vertexSet.addAll(vertices); } - processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) - .startFrom(vertexSet).queryFrom(queryURIObj) - .processWith(processorType).create(); + .startFrom(vertexSet).queryFrom(queryURIObj).format(format) + .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); } else if (!queryURI.equals("")){ processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) .queryFrom(queryURIObj) - .processWith(processorType).create(); + .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); } else { processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton) .queryFrom(gremlin, "gremlin") - .processWith(processorType).create(); + .processWith(processorType).traversalSource(isHistory(format), traversalSource).create(); } - String result = ""; List<Object> vertTemp = processor.execute(subGraphStyle); List<Object> vertices = traversalUriHttpEntry.getPaginatedVertexList(vertTemp); - - DBSerializer serializer = new DBSerializer(version, dbEngine, introspectorFactoryType, sourceOfTruth); + + DBSerializer serializer = new DBSerializer(version, dbEngine, ModelType.MOXY, sourceOfTruth); FormatFactory ff = new FormatFactory(traversalUriHttpEntry.getLoader(), serializer, schemaVersions, this.basePath); - - Formatter formater = ff.get(format, info.getQueryParameters()); - - result = formater.output(vertices).toString(); - double msecs = StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long)msecs,TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - LOGGER.info ("Completed"); - + MultivaluedMap<String, String> mvm = new MultivaluedHashMap<>(); + mvm.putAll(info.getQueryParameters()); + if (isHistory(format)) { + mvm.putSingle("startTs", Long.toString(getStartTime(format, mvm))); + mvm.putSingle("endTs", Long.toString(getEndTime(mvm))); + } + Formatter formatter = ff.get(format, mvm); + + String result = formatter.output(vertices).toString(); + + //LOGGER.info ("Completed"); + + String acceptType = headers.getHeaderString("Accept"); + + if(acceptType == null){ + acceptType = MediaType.APPLICATION_JSON; + } + + if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ + result = xmlFormatTransformer.transform(result); + } + if(traversalUriHttpEntry.isPaginated()){ response = Response.status(Status.OK) - .type(MediaType.APPLICATION_JSON) + .type(acceptType) .header("total-results", traversalUriHttpEntry.getTotalVertices()) .header("total-pages", traversalUriHttpEntry.getTotalPaginationBuckets()) .entity(result) .build(); }else { response = Response.status(Status.OK) - .type(MediaType.APPLICATION_JSON) + .type(acceptType) .entity(result).build(); } } catch (AAIException e) { @@ -274,8 +261,6 @@ public class QueryConsumer extends RESTAPI { AAIException ex = new AAIException("AAI_4000", e); response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); } finally { - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); if (dbEngine != null) { dbEngine.rollback(); } @@ -289,7 +274,7 @@ public class QueryConsumer extends RESTAPI { if (params.containsKey("depth") && params.getFirst("depth").matches("\\d+")) { String depth = params.getFirst("depth"); - Integer i = Integer.parseInt(depth); + int i = Integer.parseInt(depth); if (i > 1) { throw new AAIException("AAI_3303"); } @@ -310,8 +295,6 @@ public class QueryConsumer extends RESTAPI { } private CustomQueryConfig getCustomQueryConfig(URI uriObj ) { - - CustomQueryConfig customQueryConfig; String path = uriObj.getPath(); String[] parts = path.split("/"); @@ -329,77 +312,61 @@ public class QueryConsumer extends RESTAPI { } - private Response createMessageMissingQueryRequiredParameters(List<String> missingRequiredQueryParams, HttpHeaders headers, UriInfo info, HttpServletRequest req) { + private Response createMessageMissingQueryRequiredParameters(List<String> missingRequiredQueryParams, HttpHeaders headers) { AAIException e = new AAIException("AAI_3013"); ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(missingRequiredQueryParams.toString()); - if (templateVars.isEmpty()) { - templateVars.add(missingRequiredQueryParams.toString()); - } - - Response response = Response + return Response .status(e.getErrorObject().getHTTPResponseCode()) .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)).build(); - - return response; - } + } - private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers, UriInfo info, HttpServletRequest req) { + private Response createMessageInvalidQuerySection(String invalidQuery, HttpHeaders headers) { AAIException e = new AAIException("AAI_3014"); ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(invalidQuery); - if (templateVars.isEmpty()) { - templateVars.add(invalidQuery); - } - - Response response = Response + return Response .status(e.getErrorObject().getHTTPResponseCode()) .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)).build(); - - return response; - } + } - public List<String> checkForInvalidQueryParameters( CustomQueryConfig customQueryConfig, MultivaluedMap<String, String> queryParams) { + private List<String> checkForInvalidQueryParameters( CustomQueryConfig customQueryConfig, MultivaluedMap<String, String> queryParams) { - List<String> allParameters = new ArrayList<String>(); + List<String> allParameters = new ArrayList<>(); /* * Add potential Required and Optional to allParameters */ Optional.ofNullable(customQueryConfig.getQueryOptionalProperties()).ifPresent(allParameters::addAll); Optional.ofNullable(customQueryConfig.getQueryRequiredProperties()).ifPresent(allParameters::addAll); - if(queryParams.isEmpty()) + if(queryParams.isEmpty()) { return new ArrayList<>(); - List<String> invalidParameters = queryParams.keySet().stream() - .filter(param -> !allParameters.contains(param)) - .collect(Collectors.toList()); - - return invalidParameters; - + } + return queryParams.keySet().stream() + .filter(param -> !allParameters.contains(param)) + .collect(Collectors.toList()); } - private Response createMessageInvalidQueryParameters(List<String> invalidQueryParams, HttpHeaders headers, UriInfo info, HttpServletRequest req) { + private Response createMessageInvalidQueryParameters(List<String> invalidQueryParams, HttpHeaders headers) { AAIException e = new AAIException("AAI_3022"); ArrayList<String> templateVars = new ArrayList<>(); + templateVars.add(invalidQueryParams.toString()); - if (templateVars.isEmpty()) { - templateVars.add(invalidQueryParams.toString()); - } - - Response response = Response + return Response .status(e.getErrorObject().getHTTPResponseCode()) - .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, + .entity(ErrorLogHelper.getRESTAPIErrorResponse( + headers.getAcceptableMediaTypes(), + e, templateVars)).build(); - return response; - } - - + } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java index 3154087..2e43e5b 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/RecentAPIConsumer.java @@ -19,34 +19,12 @@ */ package org.onap.aai.rest; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.MultivaluedMap; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; -import javax.ws.rs.core.UriInfo; - import org.onap.aai.concurrent.AaiCallable; -import org.onap.aai.dbmap.DBConnectionType; - import org.onap.aai.exceptions.AAIException; -import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.ModelType; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; -import org.onap.aai.setup.SchemaVersion; -import org.onap.aai.setup.SchemaVersions; + import org.onap.aai.rest.db.HttpEntry; -import org.onap.aai.rest.dsl.DslQueryProcessor; import org.onap.aai.rest.search.GenericQueryProcessor; import org.onap.aai.rest.search.GremlinServerSingleton; import org.onap.aai.rest.search.QueryProcessorType; @@ -58,16 +36,22 @@ import org.onap.aai.serialization.queryformats.Format; import org.onap.aai.serialization.queryformats.FormatFactory; import org.onap.aai.serialization.queryformats.Formatter; import org.onap.aai.serialization.queryformats.SubGraphStyle; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.StopWatch; - +import org.onap.aai.setup.SchemaVersion; +import org.onap.aai.setup.SchemaVersions; +import org.onap.aai.transforms.XmlFormatTransformer; import org.onap.aai.util.AAIConstants; import org.onap.aai.util.TraversalConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; +import java.util.List; +import java.util.concurrent.TimeUnit; + @Path("/recents/{version: v[1-9][0-9]*|latest}") public class RecentAPIConsumer extends RESTAPI { @@ -77,39 +61,38 @@ public class RecentAPIConsumer extends RESTAPI { private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY; /** The query style. */ - private static final String TARGET_ENTITY = "DB"; - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(RecentAPIConsumer.class); + private static final Logger LOGGER = LoggerFactory.getLogger(RecentAPIConsumer.class); private HttpEntry traversalUriHttpEntry; - private DslQueryProcessor dslQueryProcessor; - private SchemaVersions schemaVersions; private String basePath; private GremlinServerSingleton gremlinServerSingleton; + private XmlFormatTransformer xmlFormatTransformer; + @Autowired public RecentAPIConsumer( HttpEntry traversalUriHttpEntry, - DslQueryProcessor dslQueryProcessor, SchemaVersions schemaVersions, GremlinServerSingleton gremlinServerSingleton, + XmlFormatTransformer xmlFormatTransformer, @Value("${schema.uri.base.path}") String basePath ){ this.traversalUriHttpEntry = traversalUriHttpEntry; - this.dslQueryProcessor = dslQueryProcessor; this.schemaVersions = schemaVersions; this.gremlinServerSingleton = gremlinServerSingleton; + this.xmlFormatTransformer = xmlFormatTransformer; this.basePath = basePath; } @GET @Path("/{nodeType: .+}") @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) public Response getRecentData(String content, @PathParam("version") String versionParam, @PathParam("nodeType") String nodeType, @Context HttpHeaders headers, @Context UriInfo info) { @@ -126,15 +109,12 @@ public class RecentAPIConsumer extends RESTAPI { public Response processRecentData(String content, @PathParam("version") String versionParam, @PathParam("nodeType") String nodeType, @Context UriInfo info, @Context HttpHeaders headers) { - String methodName = "processRecentData"; String sourceOfTruth = headers.getRequestHeaders().getFirst("X-FromAppId"); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); String queryProcessor = headers.getRequestHeaders().getFirst("QueryProcessor"); QueryProcessorType processorType = this.processorType; - Response response = null; + Response response; TransactionalGraphEngine dbEngine = null; try { - LoggingContext.save(); if (queryProcessor != null) { processorType = QueryProcessorType.valueOf(queryProcessor); @@ -143,8 +123,7 @@ public class RecentAPIConsumer extends RESTAPI { SchemaVersion version = new SchemaVersion(versionParam); this.checkVersion(version); - DBConnectionType type = this.determineConnectionType(sourceOfTruth, realTime); - traversalUriHttpEntry.setHttpEntryProperties(version, type); + traversalUriHttpEntry.setHttpEntryProperties(version); dbEngine = traversalUriHttpEntry.getDbEngine(); /* @@ -156,10 +135,7 @@ public class RecentAPIConsumer extends RESTAPI { GenericQueryProcessor processor = null; - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - LoggingContext.startTime(); - StopWatch.conditionalStart(); + processor = new GenericQueryProcessor.Builder(dbEngine, gremlinServerSingleton).queryFrom(nodeType, "nodeQuery") .uriParams(info.getQueryParameters()) @@ -179,12 +155,19 @@ public class RecentAPIConsumer extends RESTAPI { result = formater.output(vertices).toString(); - double msecs = StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long) msecs, TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - LOGGER.info("Completed"); + //LOGGER.info("Completed"); + + String acceptType = headers.getHeaderString("Accept"); + + if(acceptType == null){ + acceptType = MediaType.APPLICATION_JSON; + } + + if(MediaType.APPLICATION_XML_TYPE.isCompatible(MediaType.valueOf(acceptType))){ + result = xmlFormatTransformer.transform(result); + } - response = Response.status(Status.OK).type(MediaType.APPLICATION_JSON).entity(result).build(); + response = Response.status(Status.OK).type(acceptType).entity(result).build(); } catch (AAIException e) { response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, e); @@ -193,8 +176,6 @@ public class RecentAPIConsumer extends RESTAPI { response = consumerExceptionResponseGenerator(headers, info, HttpMethod.GET, ex); } finally { - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); if (dbEngine != null) { dbEngine.rollback(); } @@ -212,7 +193,7 @@ public class RecentAPIConsumer extends RESTAPI { public void checkNodeType(String nodeType) throws AAIException { try { - Introspector target = traversalUriHttpEntry.getLoader().introspectorFromName(nodeType); + traversalUriHttpEntry.getLoader().introspectorFromName(nodeType); } catch (AAIUnknownObjectException e) { throw new AAIException("AAI_6115", "Unrecognized nodeType [" + nodeType + "] passed to recents query."); } @@ -224,7 +205,7 @@ public class RecentAPIConsumer extends RESTAPI { if (params != null && params.containsKey("hours") && params.getFirst("hours").matches("-?\\d+")) { isHoursParameter = true; - Long hours = 0L; + long hours; try{ hours = Long.parseLong(params.getFirst("hours")); } @@ -238,7 +219,7 @@ public class RecentAPIConsumer extends RESTAPI { if (params != null && params.containsKey("date-time") && params.getFirst("date-time").matches("-?\\d+")) { isDateTimeParameter = true; Long minStartTime = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(AAIConstants.HISTORY_MAX_HOURS); - Long startTime = 0L; + Long startTime; try{ startTime = Long.parseLong(params.getFirst("date-time")); } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java b/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java new file mode 100644 index 0000000..4aa0888 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/TraversalConsumer.java @@ -0,0 +1,232 @@ +/** + * ============LICENSE_START================================================== + * org.onap.aai + * =========================================================================== + * Copyright © 2017-2020 AT&T Intellectual Property. All rights reserved. + * =========================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END==================================================== + */ +package org.onap.aai.rest; + +import org.apache.tinkerpop.gremlin.process.traversal.P; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; +import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.SubgraphStrategy; +import org.onap.aai.config.SpringContextAware; +import org.onap.aai.db.props.AAIProperties; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.rest.db.HttpEntry; +import org.onap.aai.restcore.RESTAPI; +import org.onap.aai.serialization.engines.QueryStyle; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.queryformats.Format; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; +import java.util.concurrent.TimeUnit; + +public abstract class TraversalConsumer extends RESTAPI { + + private static final String HISTORICAL_FORMAT = "state,lifecycle"; + private final boolean historyEnabled; + private final int historyTruncateWindow; + private final long currentTime = System.currentTimeMillis(); + private Long startTime = null; + private Long endTime = null; + private Long furthestInThePast = null; + + public TraversalConsumer() { + this.historyTruncateWindow = Integer.parseInt( + SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.truncate.window.days", "365")); + this.historyEnabled = Boolean.parseBoolean( + SpringContextAware.getApplicationContext().getEnvironment().getProperty("history.enabled", "false")); + } + + public boolean isHistory(Format queryFormat) { + return isHistoryEnabled() && HISTORICAL_FORMAT.contains(queryFormat.toString()); + } + + public boolean isAggregate(Format queryFormat) { + return Format.aggregate.equals(queryFormat); + } + + public boolean isHistoryEnabled() { + return historyEnabled; + } + + protected SubgraphStrategy getSubgraphStrategy(long startTs, long endTs, Format format) { + + if (Format.state.equals(format)) { + return getStateSubgraphStrategy(startTs); + } else if (Format.lifecycle.equals(format)) { + return getLifeCycleSubgraphStrategy(startTs, endTs); + } else { + return SubgraphStrategy.build() + .vertices(__.has(AAIProperties.START_TS, P.gte(startTs))) + .vertexProperties(__.has(AAIProperties.START_TS, P.gte(startTs))) + .edges(__.has(AAIProperties.START_TS, P.gte(startTs))).create(); + } + } + + private SubgraphStrategy getLifeCycleSubgraphStrategy(long startTs, long endTs) { + return SubgraphStrategy.build() + .vertices( + __.not( + __.or( + __.and( + __.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs)) + ), + __.and( + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) + ) + ) + ) + ).vertexProperties( + __.not( + __.or( + __.and( + __.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs)) + ), + __.and( + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) + ) + ) + ) + ).edges( + __.not( + __.or( + __.and( + __.has(AAIProperties.START_TS, P.gt(startTs)), + __.has(AAIProperties.START_TS, P.gt(endTs)) + ), + __.and( + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(startTs)), + __.has(AAIProperties.END_TS).has(AAIProperties.END_TS, P.lt(endTs)) + ) + ) + ) + ).create(); + } + + private SubgraphStrategy getStateSubgraphStrategy(long startTs) { + return SubgraphStrategy.build() + .vertices( + __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), + __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) + ).vertexProperties( + __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), + __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) + ).edges( + __.and(__.has(AAIProperties.START_TS, P.lte(startTs)), + __.or(__.hasNot(AAIProperties.END_TS), __.has(AAIProperties.END_TS, P.gt(startTs)))) + ).create(); + } + + + + protected GraphTraversalSource getTraversalSource(TransactionalGraphEngine dbEngine, Format format, UriInfo info) throws AAIException { + if (isHistory(format)) { + long startTime = this.getStartTime(format, info.getQueryParameters()); + long endTime = this.getEndTime(info.getQueryParameters()); + return dbEngine.asAdmin().getTraversalSource().withStrategies(getSubgraphStrategy(startTime, endTime, format)); + } + return dbEngine.asAdmin().getTraversalSource(); + } + + protected void validateHistoryParams(Format format, MultivaluedMap<String, String> params) throws AAIException { + getStartTime(format, params); + getEndTime(params); + } + + /** + * If a request comes in for information prior to our truncation timeframe, throw an error. + * In the changes api, we never return change timestamps prior to the truncation timeframe. + * In the lifecycle api, we should treat a call with no timestamp as a lifecycle since call with a timestamp of the truncation time + * in the lifecycle api, we should return an error if the timestamp provided is prior to the truncation time + * In the state api, we should return an error if the timestamp provided is prior to the truncation time + * @param params + * @return + */ + protected long getStartTime(Format format, MultivaluedMap<String, String> params) throws AAIException { + + if (startTime != null) { + return startTime; + } + + String startTs = params.getFirst("startTs") ; + + if (Format.state.equals(format)) { + if (startTs == null || startTs.isEmpty() || "-1".equals(startTs) || "now".equals(startTs)) { + startTime = currentTime; + } else { + startTime = Long.valueOf(startTs); + verifyTimeAgainstTruncationTime(startTime); + } + } else if (Format.lifecycle.equals(format)) { + if("now".equals(startTs)) { + startTime = currentTime; + } else if (startTs == null || startTs.isEmpty()|| "-1".equals(startTs)) { + startTime = getFurthestInThePast(); + } else { + startTime = Long.valueOf(startTs); + verifyTimeAgainstTruncationTime(startTime); + } + } + + return startTime; + + } + + private void verifyTimeAgainstTruncationTime(long timestamp) throws AAIException { + if (timestamp < getFurthestInThePast()) { + throw new AAIException("AAI_4019"); + } + } + + protected long getEndTime(MultivaluedMap<String, String> params) throws AAIException { + if (endTime != null) { + return endTime; + } + + String endTs = params.getFirst("endTs") ; + + if (endTs == null || endTs.isEmpty() || "-1".equals(endTs) || "now".equals(endTs)) { + endTime = currentTime; + } else { + endTime = Long.valueOf(endTs); + verifyTimeAgainstTruncationTime(endTime); + } + + return endTime; + } + + protected Long getFurthestInThePast() { + if (furthestInThePast == null) { + furthestInThePast = currentTime - TimeUnit.DAYS.toMillis(historyTruncateWindow); + } + return furthestInThePast; + } + + protected QueryStyle getQueryStyle(Format format, HttpEntry traversalUriHttpEntry) { + if (isHistory(format)) { + return QueryStyle.HISTORY_TRAVERSAL; + } + return traversalUriHttpEntry.getQueryStyle(); + } + +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java index 9ffa69b..cf7f51d 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslContext.java @@ -19,13 +19,13 @@ */ package org.onap.aai.rest.dsl; +import org.antlr.v4.runtime.ParserRuleContext; + import java.util.ArrayList; import java.util.Deque; import java.util.LinkedList; import java.util.List; -import org.antlr.v4.runtime.ParserRuleContext; - public class DslContext { private ParserRuleContext ctx; @@ -33,7 +33,7 @@ public class DslContext { private boolean validationFlag = true; private boolean isStartNode = false; private String startNode = ""; - private List<String> startNodeKeys = new ArrayList<String>(); + private List<String> startNodeKeys = new ArrayList<>(); private String currentNode; private String previousNode; @@ -45,13 +45,13 @@ public class DslContext { private String whereStartNode = ""; - private Deque<String> unionStartNodes = new LinkedList<String>(); + private Deque<String> unionStartNodes = new LinkedList<>(); /* * Limit Queries have to be applied in the end - so i have to set this in * context */ - StringBuilder limitQuery = new StringBuilder(); + public StringBuilder limitQuery = new StringBuilder(); public ParserRuleContext getCtx() { return ctx; diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java index 6817cf7..3d324ad 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryBuilder.java @@ -19,21 +19,26 @@ */ package org.onap.aai.rest.dsl; -import com.google.common.base.Joiner; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.edges.EdgeRule; import org.onap.aai.edges.EdgeRuleQuery; +import org.onap.aai.edges.enums.AAIDirection; import org.onap.aai.edges.enums.EdgeType; import org.onap.aai.edges.exceptions.EdgeRuleNotFoundException; import org.onap.aai.introspection.Introspector; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.exceptions.AAIUnknownObjectException; import org.onap.aai.schema.enums.PropertyMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.StringUtils; import java.util.List; import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.stream.Collectors; public class DslQueryBuilder { @@ -43,6 +48,8 @@ public class DslQueryBuilder { private StringBuilder query; private StringBuilder queryException; + private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryBuilder.class); + public DslQueryBuilder(EdgeIngestor edgeIngestor, Loader loader) { this.edgeRules = edgeIngestor; this.loader = loader; @@ -74,6 +81,19 @@ public class DslQueryBuilder { /* * DSL always dedupes the results */ + public DslQueryBuilder end(long selectCounter) { + if(selectCounter <= 0) { + return this.end(); + } else { + String selectStep = "step" + selectCounter; + query.append(".as('").append(selectStep).append("')").append(".as('stepMain')" + + ".select('").append(selectStep).append("')").append(".store('x')").append(".select('stepMain').fold().dedup()"); + } + return this; + } + + + public DslQueryBuilder end() { query.append(".cap('x').unfold().dedup()"); return this; @@ -85,6 +105,21 @@ public class DslQueryBuilder { } public DslQueryBuilder edgeQuery(List<String> edgeLabels, String aNode, String bNode) { + EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(aNode, bNode); + return edgeQueryWithBuilder(edgeLabels, aNode, bNode, baseQ); + } + + public DslQueryBuilder edgeQuery(Edge edge, String aNode, String bNode) { + List<String> edgeLabels = edge.getLabels().stream().map(edgeLabel -> StringUtils.quote(edgeLabel.getLabel())).collect(Collectors.toList()); + EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(aNode, bNode); + + if((AAIDirection.valueOf(edge.getDirection().name())) != AAIDirection.BOTH) { + baseQ = baseQ.direction(AAIDirection.valueOf(edge.getDirection().name())); + } + return edgeQueryWithBuilder(edgeLabels, aNode, bNode, baseQ); + } + + private DslQueryBuilder edgeQueryWithBuilder(List<String> edgeLabels, String aNode, String bNode, EdgeRuleQuery.Builder edgeBuilder) { //TODO : change this for fuzzy search. String edgeType = ""; @@ -94,48 +129,42 @@ public class DslQueryBuilder { if (!edgeLabels.isEmpty()) { edgeTraversalClause = ".createEdgeTraversalWithLabels("; - edgeLabelsClause = String.join("", ", new ArrayList<>(Arrays.asList(", Joiner.on(",").join(edgeLabels), "))"); + edgeLabelsClause = String.join("", ", new ArrayList<>(Arrays.asList(", String.join(",", edgeLabels), "))"); } + LOGGER.debug("EdgeLabels Clause: {}", edgeLabelsClause); - EdgeRuleQuery.Builder baseQ = new EdgeRuleQuery.Builder(aNode, bNode); Multimap<String, EdgeRule> rules = ArrayListMultimap.create(); try { - //TODO chnage this - ugly if (edgeLabels.isEmpty()) { - rules.putAll(edgeRules.getRules(baseQ.build())); + rules.putAll(edgeRules.getRules(edgeBuilder.build())); } else { - edgeLabels.stream().forEach(label -> { + edgeLabels.forEach(label -> { try { - rules.putAll(edgeRules.getRules(baseQ.label(label).build())); + rules.putAll(edgeRules.getRules(edgeBuilder.label(label).build())); } catch (EdgeRuleNotFoundException e) { - queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode - + ", " + bNode + label); - + queryException.append("Exception while finding the edge rule between the nodeTypes: ").append(aNode).append(", ").append(bNode).append(label); } }); } } catch (EdgeRuleNotFoundException e) { if (!edgeLabels.isEmpty()) { - queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode - + ", " + bNode + edgeLabels.stream().toString()); + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode).append(edgeLabels.stream().toString()); } else { - queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode - + ", " + bNode); + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode); } return this; } if (rules.isEmpty() || rules.keys().isEmpty()) { - queryException.append("AAI_6120" + "No EdgeRule found for passed nodeTypes: " + aNode - + ", " + bNode); + queryException.append("- No EdgeRule found for passed nodeTypes: ").append(aNode).append(", ").append(bNode); } else { if (edgeLabels.isEmpty()) { - if (edgeRules.hasRule(baseQ.edgeType(EdgeType.TREE).build())) { + if (edgeRules.hasRule(edgeBuilder.edgeType(EdgeType.TREE).build())) { edgeType = "EdgeType.TREE" + ","; } - if (edgeRules.hasRule(baseQ.edgeType(EdgeType.COUSIN).build())) { + if (edgeRules.hasRule(edgeBuilder.edgeType(EdgeType.COUSIN).build())) { if (edgeType.isEmpty()) { edgeType = "EdgeType.COUSIN" + ","; } else { @@ -152,13 +181,19 @@ public class DslQueryBuilder { } - public DslQueryBuilder where() { + public DslQueryBuilder where(boolean isNot) { query.append(".where("); + if(isNot){ + query.append("builder.newInstance().not("); + } return this; } - public DslQueryBuilder endWhere() { + public DslQueryBuilder endWhere(boolean isNot) { query.append(")"); + if(isNot){ + query.append(")"); + } return this; } @@ -168,12 +203,14 @@ public class DslQueryBuilder { } public DslQueryBuilder filter(boolean isNot, String node, String key, List<String> values) { - return this.filterPropertyStart(isNot).filterPropertyKeys(node, key, values).filterPropertyEnd(); + return this.filterPropertyStart(isNot,values).filterPropertyKeys(node, key, values).filterPropertyEnd(); } - public DslQueryBuilder filterPropertyStart(boolean isNot) { + public DslQueryBuilder filterPropertyStart(boolean isNot, List<String> values) { if (isNot) { query.append(".getVerticesExcludeByProperty("); + } else if(values!= null && !values.isEmpty() && Boolean.parseBoolean(values.get(0))) { + query.append(".getVerticesByBooleanProperty("); } else { query.append(".getVerticesByProperty("); } @@ -188,46 +225,63 @@ public class DslQueryBuilder { public DslQueryBuilder validateFilter(String node, List<String> keys) { try { Introspector obj = loader.introspectorFromName(node); + if (keys.isEmpty()) { - queryException.append("No keys sent. Valid keys for " + node + " are " - + String.join(",", obj.getIndexedProperties())); + queryException.append("No keys sent. Valid keys for ") + .append(node) + .append(" are ") + .append(String.join(",", obj.getIndexedProperties())); return this; } - boolean notIndexed = keys.stream() - .filter(prop -> obj.getIndexedProperties().contains(prop)).collect(Collectors.toList()).isEmpty(); - - if (notIndexed) { - queryException.append("Non indexed keys sent. Valid keys for " + node + " " - + String.join(",", obj.getIndexedProperties())); - } } catch (AAIUnknownObjectException e) { - queryException.append("Unknown Object being referenced by the query" + node); + queryException.append("Unknown Object being referenced by the query").append(node); } return this; } + public DslQueryBuilder select(boolean isNot, long selectCounter, List<String> keys) { + /* + * TODO : isNot should look at the vertex properties and include everything except the notKeys + */ + + Pattern p = Pattern.compile("aai-node-type"); + Matcher m = p.matcher(query); + int count = 0; + while (m.find()){ + count++; + } + + if (selectCounter == count || keys == null) { + String selectStep = "step" + selectCounter; +// String keysArray = String.join(",", keys); + query.append(".as('").append(selectStep).append("')") + .append(".as('stepMain').select('").append(selectStep).append("')"); + } + return this; + } + public DslQueryBuilder filterPropertyKeys(String node, String key, List<String> values) { try { Introspector obj = loader.introspectorFromName(node); - - Optional<String> alias = obj.getPropertyMetadata(key, PropertyMetadata.DB_ALIAS); + Optional<String> alias = obj.getPropertyMetadata(key.replace("'",""), PropertyMetadata.DB_ALIAS); if (alias.isPresent()) { - key = alias.get(); + key = StringUtils.quote(alias.get()); } + query.append(key); if (!values.isEmpty()) { if (values.size() > 1) { String valuesArray = String.join(",", values); - query.append(",").append(" new ArrayList<>(Arrays.asList(" + valuesArray + "))"); + query.append(",").append(" new ArrayList<>(Arrays.asList(").append(valuesArray).append("))"); } else { query.append(",").append(values.get(0)); } } } catch (AAIUnknownObjectException e) { - queryException.append("Unknown Object being referenced by the query" + node); + queryException.append("Unknown Object being referenced by the query").append(node); } return this; } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java index a3978fd..14663e1 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslQueryProcessor.java @@ -19,86 +19,151 @@ */ package org.onap.aai.rest.dsl; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; -import org.antlr.v4.runtime.CharStreams; -import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.misc.ParseCancellationException; import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeListener; import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.onap.aai.AAIDslLexer; -import org.onap.aai.AAIDslParser; import org.onap.aai.exceptions.AAIException; +import org.onap.aai.rest.dsl.v2.DslListener; +import org.onap.aai.rest.dsl.validation.DslValidator; +import org.onap.aai.rest.enums.QueryVersion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; - +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** * The Class DslQueryProcessor. */ public class DslQueryProcessor { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslQueryProcessor.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DslQueryProcessor.class); + + private Map<QueryVersion, ParseTreeListener> dslListeners; + private boolean startNodeValidationFlag = true; + private String validationRules = ""; + private String packageName = "org.onap.aai.dsl."; + private static final String LEXER = "AAIDslLexer"; + private static final String PARSER = "AAIDslParser"; + private static final String EOF_TOKEN = "<EOF>"; - private DslListener dslListener; - private boolean validationFlag = true; + private boolean isAggregate = false; @Autowired - public DslQueryProcessor(DslListener dslListener) { - this.dslListener = dslListener; + public DslQueryProcessor(Map<QueryVersion, ParseTreeListener> dslListeners) { + this.dslListeners = dslListeners; } - public String parseAaiQuery(String aaiQuery) throws AAIException { + public Map<String, Object> parseAaiQuery(QueryVersion version, String aaiQuery) throws AAIException { + Map<String, Object> resultMap = new HashMap<>(); try { // Create a input stream that reads our string InputStream stream = new ByteArrayInputStream(aaiQuery.getBytes(StandardCharsets.UTF_8)); - // Create a lexer from the input CharStream - AAIDslLexer lexer = new AAIDslLexer(CharStreams.fromStream(stream, StandardCharsets.UTF_8)); + packageName = packageName + version.toString().toLowerCase() + "."; + + Class<?> lexerClass = Class.forName(packageName + LEXER); + Class<?> parserClass = Class.forName(packageName + PARSER); + + Lexer lexer = (Lexer)lexerClass.getConstructor(CharStream.class).newInstance(CharStreams.fromStream(stream, StandardCharsets.UTF_8)); lexer.removeErrorListeners(); lexer.addErrorListener(new AAIDslErrorListener()); - - // Get a list of tokens pulled from the lexer CommonTokenStream tokens = new CommonTokenStream(lexer); // Parser that feeds off of the tokens buffer - AAIDslParser parser = new AAIDslParser(tokens); - parser.removeErrorListeners(); // remove ConsoleErrorListener + Parser parser = (Parser)parserClass.getConstructor(TokenStream.class).newInstance(tokens); + parser.removeErrorListeners(); parser.addErrorListener(new AAIDslErrorListener()); + ParseTreeListener dslListener = dslListeners.get(version); + dslListener.getClass().getMethod("setValidationFlag", boolean.class).invoke(dslListener, isStartNodeValidationFlag()); + dslListener.getClass().getMethod("setAggregateFlag", boolean.class).invoke(dslListener,isAggregate()); - dslListener.setValidationFlag(isValidationFlag()); - // Specify our entry point - ParseTree ptree = parser.aaiquery(); - LOGGER.info("QUERY-interim" + ptree.toStringTree(parser)); + if(!getValidationRules().isEmpty() && !"none".equals(getValidationRules())) { + DslValidator validator = new DslValidator.Builder() + .create(); + dslListener.getClass().getMethod("setQueryValidator", DslValidator.class, String.class).invoke(dslListener, validator, getValidationRules()); + } + // Specify our entry point + ParseTree ptree = (ParseTree)parserClass.getMethod("aaiquery").invoke(parser); + + // Check if there is no EOF token at the end of the parsed aaiQuery + // If none, DSL query may have not been parsed correctly and omitted part of the query out. If so error out. + // If it wasn't expecting a opening parens after a closing bracket for union, it will drop the proceeding part of the query. + Token eofToken = tokens.get(tokens.size() - 1); + if (eofToken != null && !eofToken.getText().equals(EOF_TOKEN)) { + if (eofToken.getText().equals("(")) { + throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query: DSL Query could not be parsed correctly. Please check your syntax."); + } + } + + if (LOGGER.isInfoEnabled()) { + LOGGER.info("QUERY-interim {}", ptree.toStringTree(parser)); + } // Walk it and attach our listener ParseTreeWalker walker = new ParseTreeWalker(); + walker.walk(dslListener, ptree); - LOGGER.info("Final QUERY" + dslListener.getQuery()); - - /* - * TODO - Visitor patternQueryDslVisitor visitor = new - * QueryDslVisitor(); String query = visitor.visit(ptree); - * - */ - return dslListener.getQuery(); - } catch(ParseCancellationException e){ - throw new AAIException("AAI_6149", "DSL Syntax Error while processing the query :" + e.getMessage()); - } catch(AAIException e) { - throw new AAIException("AAI_6149", "DSL Syntax Error while processing the query :" + e.getMessage()); + String query = (String) dslListener.getClass().getMethod("getQuery").invoke(dslListener); + resultMap.put("query", query); + if (version.equals(QueryVersion.V2)){ + Map<String, List<String>> selectKeys= ((DslListener)dslListener).getSelectKeys(); + if (selectKeys != null && !selectKeys.isEmpty()){ + resultMap.put("propertiesMap", selectKeys); + } + } + LOGGER.info("Final QUERY {}", query); + return resultMap; + }catch(InvocationTargetException e){ + if (e.getTargetException() instanceof ParseCancellationException) { + throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query :" + e.getTargetException().getMessage()); + } else if (e.getTargetException() instanceof AAIException) { + AAIException ex = (AAIException)e.getTargetException(); + throw new AAIException((ex.getCode().isEmpty() ? "AAI_6149":ex.getCode()), "DSL Error while processing the query :" + ex.getMessage()); + } else { + throw new AAIException("AAI_6152","Exception while processing DSL query"); + } + + } catch(ParseCancellationException e) { + throw new AAIException("AAI_6153", "DSL Syntax Error while processing the query: " + e.getMessage()); + } catch (Exception e) { - throw new AAIException("AAI_6149","Error while processing the query :" + e.getMessage()); + throw new AAIException("AAI_6152","Error while processing the query: " + e.getMessage()); + } } - public boolean isValidationFlag() { - return validationFlag; + + public boolean isStartNodeValidationFlag() { + return startNodeValidationFlag; + } + + public void setStartNodeValidationFlag(boolean startNodeValidationFlag) { + this.startNodeValidationFlag = startNodeValidationFlag; + } + + public boolean isAggregate() { + return isAggregate; + } + + public void setAggregate(boolean aggregate) { + this.isAggregate = aggregate; + } + + public String getValidationRules() { + return validationRules; } - public void setValidationFlag(boolean validationFlag) { - this.validationFlag = validationFlag; + public void setValidationRules(String validationRules) { + this.validationRules = validationRules; } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java new file mode 100644 index 0000000..c3be5dc --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/Edge.java @@ -0,0 +1,59 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl; + +import org.onap.aai.rest.enums.EdgeDirection; + +import java.util.List; +import java.util.stream.Collectors; + +public class Edge { + + private List<EdgeLabel> labels; + private EdgeDirection direction; + + public Edge (EdgeDirection direction, List<EdgeLabel> labels) { + this.labels = labels; + this.direction = direction; + } + + public List<EdgeLabel> getLabels() { + return labels; + } + + public void setLabels(List<EdgeLabel> labels) { + this.labels = labels; + } + + public EdgeDirection getDirection() { + return direction; + } + + public void setDirection(EdgeDirection direction) { + this.direction = direction; + } + + @Override + public String toString() { + return String.format("labels: %s, direction: %s ", + labels.stream().map(EdgeLabel::getLabel).collect(Collectors.joining(",")), + this.getDirection().name()); + } +}
\ No newline at end of file diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java new file mode 100644 index 0000000..703adaf --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/EdgeLabel.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl; + +public class EdgeLabel { + + private String label; + private boolean isExactMatch; + + public EdgeLabel (String label, boolean isExactMatch) { + this.isExactMatch = isExactMatch; + this.label = label; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public boolean isExactMatch() { + return isExactMatch; + } + + public void setExactMatch(boolean isExactMatch) { + this.isExactMatch = isExactMatch; + } + +}
\ No newline at end of file diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java index 8fd23cc..4bb093e 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/DslListener.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v1/DslListener.java @@ -17,25 +17,26 @@ * limitations under the License. * ============LICENSE_END========================================================= */ -package org.onap.aai.rest.dsl; +package org.onap.aai.rest.dsl.v1; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; import com.google.common.collect.Lists; -import org.onap.aai.AAIDslBaseListener; -import org.onap.aai.AAIDslParser; +import org.onap.aai.dsl.v1.AAIDslBaseListener; +import org.onap.aai.dsl.v1.AAIDslParser; import org.onap.aai.edges.EdgeIngestor; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.ModelType; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.rest.dsl.DslQueryBuilder; +import org.onap.aai.rest.dsl.validation.DslValidator; +import org.onap.aai.rest.dsl.validation.DslValidatorRule; import org.onap.aai.setup.SchemaVersions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -44,17 +45,29 @@ import java.util.stream.Stream; */ public class DslListener extends AAIDslBaseListener { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(DslListener.class); + private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class); - boolean validationFlag = false; - EdgeIngestor edgeIngestor; - Loader loader; + private boolean validationFlag = false; + private EdgeIngestor edgeIngestor; + private Loader loader; + private Optional<DslValidator> queryValidator = Optional.empty(); + private boolean hasReturnValue = false; + + private String validationRules = "none"; private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); private Deque<String> traversedNodes = new LinkedList<>(); private Deque<List<String>> returnedNodes = new LinkedList<>(); - List<String> traversedEdgeLabels = new LinkedList<>(); + private List<String> traversedEdgeLabels = new LinkedList<>(); + + private boolean isAggregate = false; + + /* + * Additional datastructures to store all nodeCount & looped edges + */ + private int nodeCount = 0; + private List<String> traversedEdges = new LinkedList<>(); /** * Instantiates a new DslListener. @@ -70,12 +83,20 @@ public class DslListener extends AAIDslBaseListener { } public String getQuery() throws AAIException { - //TODO Change the exception reporting if (!getException().isEmpty()) { - LOGGER.error("Exception in the DSL Query" + getException()); - throw new AAIException("AAI_6149", getException()); + AAIException aaiException = new AAIException("AAI_6149", getException()); + ErrorLogHelper.logException(aaiException); + throw aaiException; } + DslValidatorRule ruleValidator = new DslValidatorRule.Builder() + .loop(getValidationRules() , traversedEdges) + .nodeCount(getValidationRules(), nodeCount).build(); + if(queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)){ + AAIException aaiException = new AAIException("AAI_6151", "Validation error " + queryValidator.get().getErrorMessage() ); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } return this.compile(); } @@ -85,7 +106,8 @@ public class DslListener extends AAIDslBaseListener { } public String getException() { - return builder().getQueryException().toString(); + List<String> exceptions = dslQueryBuilders.stream().map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); + return String.join("", Lists.reverse(exceptions)); } @Override @@ -94,6 +116,13 @@ public class DslListener extends AAIDslBaseListener { } @Override + public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { + if (!hasReturnValue) { + throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); + } + } + + @Override public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { builder().start(); } @@ -124,7 +153,6 @@ public class DslListener extends AAIDslBaseListener { if(!ctx.traversal().isEmpty()) { count += ctx.traversal().size() ; } - //TODO so ugly String resultNode = traversedNodes.peekFirst(); if (!traversedNodes.isEmpty()) { @@ -147,6 +175,7 @@ public class DslListener extends AAIDslBaseListener { if (!traversedNodes.isEmpty()) { builder().edgeQuery(traversedEdgeLabels, traversedNodes.peekFirst(), ctx.label().getText()); + traversedEdges.add(traversedNodes.peekFirst() + ctx.label().getText()); } else { builder().nodeQuery(ctx.label().getText()); } @@ -164,15 +193,17 @@ public class DslListener extends AAIDslBaseListener { if (ctx.filter() != null) { allKeys = ctx.filter().propertyFilter().stream().flatMap( pf -> pf.key().stream()).map( - e -> e.getText().replaceAll("\'", "")).collect(Collectors.toList()); + e -> e.getText().replaceFirst("\'", "").substring(0, e.getText().length() - 2)).collect(Collectors.toList()); } builder().validateFilter(ctx.label().getText(), allKeys); } if (ctx.store() != null) { builder().store(); + hasReturnValue = true; } traversedEdgeLabels = new ArrayList<>(); + nodeCount++; } @@ -187,12 +218,17 @@ public class DslListener extends AAIDslBaseListener { String resultNode = returnedNodes.pop().get(0); traversedNodes.addFirst(resultNode); builder().endUnion(); + if (ctx.store() != null) { + builder().store(); + hasReturnValue = true; + } } @Override public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); returnedNodes.addFirst(new ArrayList<>()); - builder().where(); + builder().where(isNot); } @Override @@ -200,15 +236,8 @@ public class DslListener extends AAIDslBaseListener { if(!returnedNodes.isEmpty()) { returnedNodes.pop(); } - builder().endWhere(); - } - - @Override - public void enterTraversal(AAIDslParser.TraversalContext ctx) { - } - - @Override - public void enterEdge(AAIDslParser.EdgeContext ctx) { + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + builder().endWhere(isNot); } @Override @@ -218,11 +247,6 @@ public class DslListener extends AAIDslBaseListener { } @Override - public void enterFilter(AAIDslParser.FilterContext ctx) { - - } - - @Override public void enterPropertyFilter(AAIDslParser.PropertyFilterContext ctx) { List<AAIDslParser.KeyContext> valueList = ctx.key(); @@ -231,17 +255,26 @@ public class DslListener extends AAIDslBaseListener { boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); List<AAIDslParser.NumContext> numberValues = ctx.num(); + List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); + /* * Add all String values */ List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) - .map(value -> "'" + value.getText().replace("'", "") + "'").collect(Collectors.toList()); + .map(value -> value.getText()).collect(Collectors.toList()); + /* * Add all numeric values */ values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) .map(value -> value.getText()).collect(Collectors.toList())); + /* + * Add all boolean values + */ + values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); + builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); } @@ -254,4 +287,20 @@ public class DslListener extends AAIDslBaseListener { this.validationFlag = validationFlag; } + public void setQueryValidator(DslValidator queryValidator, String validationRules) { + this.queryValidator = Optional.of(queryValidator); + this.validationRules = validationRules; + } + public String getValidationRules() { + return validationRules; + } + + public void setAggregateFlag(boolean isAggregate) { + this.isAggregate = isAggregate; + } + + public boolean isAggregate(){ + return this.isAggregate; + } + } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java new file mode 100644 index 0000000..8f9f145 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/v2/DslListener.java @@ -0,0 +1,353 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl.v2; + +import com.google.common.collect.Lists; +import org.onap.aai.dsl.v2.AAIDslBaseListener; +import org.onap.aai.dsl.v2.AAIDslParser; +import org.onap.aai.edges.EdgeIngestor; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.introspection.Loader; +import org.onap.aai.introspection.LoaderFactory; +import org.onap.aai.introspection.ModelType; +import org.onap.aai.logging.ErrorLogHelper; +import org.onap.aai.rest.dsl.DslQueryBuilder; +import org.onap.aai.rest.dsl.Edge; +import org.onap.aai.rest.dsl.EdgeLabel; +import org.onap.aai.rest.dsl.validation.DslValidator; +import org.onap.aai.rest.dsl.validation.DslValidatorRule; +import org.onap.aai.rest.enums.EdgeDirection; +import org.onap.aai.setup.SchemaVersions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The Class DslListener. + */ +public class DslListener extends AAIDslBaseListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(DslListener.class.getName()); + + private boolean validationFlag = false; + private EdgeIngestor edgeIngestor; + private Loader loader; + private Optional<DslValidator> queryValidator = Optional.empty(); + private boolean hasReturnValue = false; + + private String validationRules = "none"; + + private Deque<DslQueryBuilder> dslQueryBuilders = new LinkedList<>(); + private Deque<String> traversedNodes = new LinkedList<>(); + private Deque<List<String>> returnedNodes = new LinkedList<>(); + + private Deque<Edge> traversedEdges = new ArrayDeque<>(); + private long selectCounter = 0; + + /* + * Additional datastructures to store all nodeCount & looped edges + */ + int nodeCount = 0; + private List<String> traversedEdgesOld = new LinkedList<>(); + + private Map<String, List<String>> selectKeys = new HashMap<String, List<String>>(); + private boolean isAggregate; + + public Map<String, List<String>> getSelectKeys() { + return selectKeys; + } + + public void setSelectKeys(String nodeType, List<String> properties) { + this.selectKeys.put(nodeType, properties); + } + + /** + * Instantiates a new DslListener. + */ + @Autowired + public DslListener(EdgeIngestor edgeIngestor, SchemaVersions schemaVersions, LoaderFactory loaderFactory) { + this.loader = loaderFactory.createLoaderForVersion(ModelType.MOXY, schemaVersions.getDefaultVersion()); + this.edgeIngestor = edgeIngestor; + } + + public DslQueryBuilder builder() { + return dslQueryBuilders.peekFirst(); + } + + public String getQuery() throws AAIException { + //TODO Change the exception reporting + if (!getException().isEmpty()) { + AAIException aaiException = new AAIException("AAI_6149", getException()); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + + DslValidatorRule ruleValidator = new DslValidatorRule.Builder() + .loop(getValidationRules() , traversedEdgesOld) + .nodeCount(getValidationRules(), nodeCount).build(); + if(queryValidator.isPresent() && !queryValidator.get().validate(ruleValidator)){ + AAIException aaiException = new AAIException("AAI_6151", "Validation error " + queryValidator.get().getErrorMessage() ); + ErrorLogHelper.logException(aaiException); + throw aaiException; + } + return this.compile(); + } + + public String compile() { + List<String> queries = dslQueryBuilders.stream().map(dslQb -> dslQb.getQuery().toString()).collect(Collectors.toList()); + return String.join("", Lists.reverse(queries)); + } + + public String getException() { + List<String> exceptions = dslQueryBuilders.stream().map(dslQb -> dslQb.getQueryException().toString()).collect(Collectors.toList()); + return String.join("", Lists.reverse(exceptions)); + } + + @Override + public void enterAaiquery(AAIDslParser.AaiqueryContext ctx) { + dslQueryBuilders.push(new DslQueryBuilder(edgeIngestor, loader)); + } + + @Override + public void exitAaiquery(AAIDslParser.AaiqueryContext ctx) { + if (!hasReturnValue) { + throw new RuntimeException(new AAIException("AAI_6149", "No nodes marked for output")); + } + } + + @Override + public void enterStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().start(); + } + + @Override + public void exitStartStatement(AAIDslParser.StartStatementContext ctx) { + builder().end(selectCounter); + if (!traversedNodes.isEmpty()) { + traversedNodes.removeFirst(); + } + + } + + @Override + public void exitLimit(AAIDslParser.LimitContext ctx) { + builder().limit(ctx.num().getText()); + } + + @Override + public void enterNestedStatement(AAIDslParser.NestedStatementContext ctx) { + dslQueryBuilders.addFirst(new DslQueryBuilder(edgeIngestor, loader)); + builder().startInstance(); + } + + @Override + public void exitNestedStatement(AAIDslParser.NestedStatementContext ctx) { + int count = 1; + if(!ctx.traversal().isEmpty()) { + count = ctx.traversal().size() ; + } + String resultNode = traversedNodes.peekFirst(); + + if (!traversedNodes.isEmpty()) { + Stream<Integer> integers = Stream.iterate(0, i -> i + 1); + integers.limit(count) + .forEach(i -> traversedNodes.removeFirst()); + } + List<String> resultNodes = returnedNodes.pop(); + resultNodes.add(resultNode); + returnedNodes.addFirst(resultNodes); + } + + @Override + public void enterComma(AAIDslParser.CommaContext ctx) { + builder().comma(); + } + + @Override + public void enterVertex(AAIDslParser.VertexContext ctx) { + + if (!traversedEdges.isEmpty() && !traversedNodes.isEmpty()) { + builder().edgeQuery(traversedEdges.peekFirst(), traversedNodes.peekFirst(), ctx.label().getText()); + traversedEdgesOld.add(traversedNodes.peekFirst() + ctx.label().getText()); + } else { + builder().nodeQuery(ctx.label().getText()); + } + + traversedNodes.addFirst(ctx.label().getText()); + } + + @Override + public void exitVertex(AAIDslParser.VertexContext ctx) { + + /*TODO dont use context */ + if (ctx.getParent() instanceof AAIDslParser.StartStatementContext && isValidationFlag()) { + List<String> allKeys = new ArrayList<>(); + + if (ctx.filter() != null) { + allKeys = ctx.filter().propertyFilter().stream().flatMap( + pf -> pf.key().stream()).map( + e -> e.getText().replaceAll("\'", "")).collect(Collectors.toList()); + } + builder().validateFilter(ctx.label().getText(), allKeys); + } + if (ctx.store() != null) { + if (isAggregate() && (selectCounter == nodeCount) && (nodeCount < traversedNodes.size())) { + builder().select(false, selectCounter++, null); + } + builder().store(); + hasReturnValue = true; + } + nodeCount++; + } + + + @Override + public void enterUnionVertex(AAIDslParser.UnionVertexContext ctx) { + returnedNodes.addFirst(new ArrayList<>()); + builder().union(); + } + + @Override + public void exitUnionVertex(AAIDslParser.UnionVertexContext ctx) { + String resultNode = returnedNodes.pop().get(0); + traversedNodes.addFirst(resultNode); + builder().endUnion(); + if (ctx.store() != null) { + builder().store(); + hasReturnValue = true; + } + } + + @Override + public void enterWhereFilter(AAIDslParser.WhereFilterContext ctx) { + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + returnedNodes.addFirst(new ArrayList<>()); + builder().where(isNot); + } + + @Override + public void exitWhereFilter(AAIDslParser.WhereFilterContext ctx) { + if(!returnedNodes.isEmpty()) { + returnedNodes.pop(); + } + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + builder().endWhere(isNot); + } + + @Override + public void enterEdge(AAIDslParser.EdgeContext ctx) { + List<EdgeLabel> labels = new ArrayList<>(); + + if(ctx.edgeFilter() != null) { + labels.addAll(ctx.edgeFilter().key().stream().map( + e -> new EdgeLabel(removeSingleQuotes(e.getText()), true)) + .collect(Collectors.toList())); + } + EdgeDirection direction = EdgeDirection.BOTH; + if(ctx.DIRTRAVERSE() != null){ + direction = EdgeDirection.fromValue(ctx.DIRTRAVERSE().getText()); + } + traversedEdges.addFirst(new Edge(direction, labels)); + } + + protected String removeSingleQuotes(String value) { + return value.replaceFirst("^'(.*)'$", "$1"); + } + + @Override + public void enterPropertyFilter(AAIDslParser.PropertyFilterContext ctx) { + + List<AAIDslParser.KeyContext> valueList = ctx.key(); + String filterKey = valueList.get(0).getText(); + + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + List<AAIDslParser.NumContext> numberValues = ctx.num(); + + List<AAIDslParser.BoolContext> booleanValues = ctx.bool(); + + /* + * Add all String values + */ + List<String> values = valueList.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> "'" + value.getText().replace("'", "") + "'").collect(Collectors.toList()); + /* + * Add all numeric values + */ + values.addAll(numberValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText()).collect(Collectors.toList())); + + /* + * Add all boolean values + */ + values.addAll(booleanValues.stream().filter(value -> !filterKey.equals(value.getText())) + .map(value -> value.getText().toLowerCase()).collect(Collectors.toList())); + + builder().filter(isNot, traversedNodes.peekFirst(), filterKey, values); + + } + + @Override + public void enterSelectFilter(AAIDslParser.SelectFilterContext ctx) { + + List<AAIDslParser.KeyContext> keyList = ctx.key(); + + boolean isNot = ctx.not() != null && !ctx.not().isEmpty(); + + /* + * Add all String values + */ + List<String> allKeys = keyList.stream().map(keyValue -> "'" + keyValue.getText().replace("'", "") + "'").collect(Collectors.toList()); + if (allKeys != null && !allKeys.isEmpty()){ + setSelectKeys(traversedNodes.getFirst(), allKeys); + } + if (isAggregate() && (traversedNodes.size() == nodeCount)) { + builder().select(isNot, selectCounter++, allKeys); + } + } + + public boolean isValidationFlag() { + return validationFlag; + } + + public void setValidationFlag(boolean validationFlag) { + this.validationFlag = validationFlag; + } + + public void setAggregateFlag(boolean isAggregate) { + this.isAggregate = isAggregate; + } + + public boolean isAggregate(){ + return this.isAggregate; + } + + public void setQueryValidator(DslValidator queryValidator, String validationRules) { + this.queryValidator = Optional.of(queryValidator); + this.validationRules = validationRules; + } + public String getValidationRules() { + return validationRules; + } + +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java new file mode 100644 index 0000000..53f2c72 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslQueryValidator.java @@ -0,0 +1,62 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl.validation; + +import org.onap.aai.util.AAIConfig; +import org.onap.aai.util.TraversalConstants; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +public class DslQueryValidator extends DslValidator { + + protected DslQueryValidator(Builder builder) { + super(builder); + } + + public boolean validate(DslValidatorRule dslValidatorRule) { + + return validateLoop(dslValidatorRule.isValidateLoop(), dslValidatorRule.getEdges()) && validateNodeCount(dslValidatorRule.isValidateNodeCount(), dslValidatorRule.getNodeCount()); + } + + private boolean validateLoop(boolean isValidateLoop, List<String> edges) { + if (isValidateLoop) { + Set<String> uniqueEdges = new LinkedHashSet<>(edges); + + if (uniqueEdges.size() < (edges.size() / 2)) { + this.errorMessage.append("Loop Validation failed"); + return false; + } + } + return true; + } + + private boolean validateNodeCount(boolean isValidateNodeCount, int nodeCount) { + String maxNodeString = AAIConfig.get("aai.dsl.max.nodecount", TraversalConstants.DSL_MAX_NODE_COUNT); + int maxNodeCount = Integer.parseInt(maxNodeString); + if (isValidateNodeCount && nodeCount > maxNodeCount) { + this.errorMessage.append("NodeCount Validation failed"); + return false; + } + return true; + } + +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java new file mode 100644 index 0000000..54a2feb --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslSchemaValidator.java @@ -0,0 +1,32 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl.validation; + +public class DslSchemaValidator extends DslValidator { + + protected DslSchemaValidator(Builder builder) { + super(builder); + } + + public boolean validate(DslValidatorRule dslValidatorRule) { + return true; + } + +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java new file mode 100644 index 0000000..128f8a8 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidator.java @@ -0,0 +1,58 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl.validation; + +import org.onap.aai.exceptions.AAIException; + +public abstract class DslValidator { + protected StringBuilder errorMessage = new StringBuilder(""); + + + protected DslValidator(DslValidator.Builder builder) { + + } + + public abstract boolean validate(DslValidatorRule dslValidatorRule) throws AAIException; + + public String getErrorMessage() { + return errorMessage.toString(); + } + + public static class Builder { + + boolean isSchemaValidation = false; + + public Builder schema() { + this.setSchemaValidation(true); + return this; + } + + private void setSchemaValidation(boolean schemaValidation) { + isSchemaValidation = schemaValidation; + } + + public DslValidator create() { + if (isSchemaValidation) { + return new DslSchemaValidator(this); + } + return new DslQueryValidator(this); + } + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java new file mode 100644 index 0000000..54d45bd --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/dsl/validation/DslValidatorRule.java @@ -0,0 +1,141 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2018-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.dsl.validation; + +import java.util.LinkedList; +import java.util.List; + +public class DslValidatorRule { + + private static final String LOOP_RULE = "loop"; + private static final String NODECOUNT_RULE = "nodeCount"; + private static final String ALL_RULE = "all"; + + private String query; + private boolean validateLoop; + private boolean validateNodeCount; + private int nodeCount; + private List<String> edges; + + protected DslValidatorRule(DslValidatorRule.Builder builder) { + query = builder.query; + validateLoop = builder.validateLoop; + validateNodeCount = builder.validateNodeCount; + nodeCount = builder.nodeCount; + edges = builder.getEdges(); + } + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public boolean isValidateLoop() { + return validateLoop; + } + + public void setValidateLoop(boolean validateLoop) { + this.validateLoop = validateLoop; + } + + public boolean isValidateNodeCount() { + return validateNodeCount; + } + + public void setValidateNodeCount(boolean validateNodeCount) { + this.validateNodeCount = validateNodeCount; + } + + public int getNodeCount() { + return nodeCount; + } + + public void setNodeCount(int nodeCount) { + this.nodeCount = nodeCount; + } + + public List<String> getEdges() { + return edges; + } + + public void setEdges(List<String> edges) { + this.edges = edges; + } + + public static class Builder { + + //todo optional + String query = ""; + boolean validateLoop = false; + boolean validateNodeCount = false; + int nodeCount = 0; + List<String> edges = new LinkedList<>(); + + public List<String> getEdges() { + return edges; + } + + public void setEdges(List<String> edges) { + this.edges = edges; + } + + public Builder query(String query) { + this.setQuery(query); + return this; + } + + public Builder loop(String validateLoop, List<String> edges) { + if (validateLoop.contains(LOOP_RULE) || validateLoop.contains(ALL_RULE)) { + this.setValidateLoop(true); + this.setEdges(edges); + } + + return this; + } + + public Builder nodeCount(String validateNodeCount, int nodeCount) { + if (validateNodeCount.contains(NODECOUNT_RULE) || validateNodeCount.contains(ALL_RULE)) { + this.setValidateNodeCount(true); + this.nodeCount = nodeCount; + } + return this; + } + + private void setQuery(String query) { + this.query = query; + } + + private void setValidateLoop(boolean validateLoop) { + this.validateLoop = validateLoop; + } + + private void setValidateNodeCount(boolean validateNodeCount) { + this.validateNodeCount = validateNodeCount; + } + + public DslValidatorRule build() { + + return new DslValidatorRule(this); + } + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java b/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java new file mode 100644 index 0000000..61f35ac --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/enums/EdgeDirection.java @@ -0,0 +1,48 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.enums; + +public enum EdgeDirection { + OUT(">>"), + IN("<<"), + BOTH(">"); + + + private final String value; + + private EdgeDirection(String value) { + this.value = value; + } + + + public static EdgeDirection fromValue(String value) { + + for (EdgeDirection d : values()) { + if (d.value.equals(value)) { + return d; + } + } + return BOTH; + } + @Override + public String toString() { + return value; + } +}
\ No newline at end of file diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java b/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java new file mode 100644 index 0000000..0e30f28 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/enums/QueryVersion.java @@ -0,0 +1,25 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.aai.rest.enums; + +public enum QueryVersion { + V1, + V2; +}
\ No newline at end of file diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java index 56b748c..8e62900 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GenericQueryProcessor.java @@ -19,10 +19,12 @@ */ package org.onap.aai.rest.search; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; 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; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__; import org.apache.tinkerpop.gremlin.structure.Graph; import org.apache.tinkerpop.gremlin.structure.Vertex; @@ -30,9 +32,12 @@ import org.javatuples.Pair; import org.onap.aai.exceptions.AAIException; import org.onap.aai.query.builder.MissingOptionalParameter; import org.onap.aai.rest.dsl.DslQueryProcessor; +import org.onap.aai.rest.enums.QueryVersion; import org.onap.aai.restcore.search.GroovyQueryBuilder; import org.onap.aai.restcore.util.URITools; +import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.TransactionalGraphEngine; +import org.onap.aai.serialization.queryformats.Format; import org.onap.aai.serialization.queryformats.SubGraphStyle; import javax.ws.rs.core.MultivaluedHashMap; @@ -45,7 +50,7 @@ import java.util.regex.Pattern; public abstract class GenericQueryProcessor { - private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(GenericQueryProcessor.class); + private static Logger LOGGER = LoggerFactory.getLogger(GenericQueryProcessor.class); protected final Optional<URI> uri; protected final MultivaluedMap<String, String> queryParams; @@ -57,11 +62,27 @@ public abstract class GenericQueryProcessor { protected GroovyQueryBuilder groovyQueryBuilder = new GroovyQueryBuilder(); protected final boolean isGremlin; protected Optional<DslQueryProcessor> dslQueryProcessorOptional; + + public Map<String, List<String>> getPropertiesMap() { + return propertiesList; + } + + public void setPropertiesMap(Map<String, List<String>> propertiesMap) { + this.propertiesList = propertiesMap; + } + + private Map<String, List<String>> propertiesList; /* dsl parameters to store dsl query and to check + * if this is a DSL request */ protected Optional<String> dsl; protected final boolean isDsl ; + protected boolean isHistory; + protected GraphTraversalSource traversalSource; + protected QueryStyle style; + protected QueryVersion dslApiVersion; + protected Format format; protected GenericQueryProcessor(Builder builder) { this.uri = builder.getUri(); @@ -73,16 +94,23 @@ public abstract class GenericQueryProcessor { this.isDsl = builder.isDsl(); this.gremlinServerSingleton = builder.getGremlinServerSingleton(); this.dslQueryProcessorOptional = builder.getDslQueryProcessor(); + this.dslApiVersion = builder.getDslApiVersion(); if (uri.isPresent()) { queryParams = URITools.getQueryMap(uri.get()); + } else if (builder.getUriParams() != null) { + queryParams = builder.getUriParams(); } else { queryParams = new MultivaluedHashMap<>(); } + this.traversalSource = builder.getTraversalSource(); + this.style = builder.getStyle(); + this.isHistory = builder.isHistory(); + this.format = builder.getFormat(); } - protected abstract GraphTraversal<?,?> runQuery(String query, Map<String, Object> params); - + protected abstract GraphTraversal<?,?> runQuery(String query, Map<String, Object> params, GraphTraversalSource traversalSource); + protected List<Object> processSubGraph(SubGraphStyle style, GraphTraversal<?,?> g) { final List<Object> resultVertices = new Vector<>(); g.store("y"); @@ -106,18 +134,45 @@ public abstract class GenericQueryProcessor { Pair<String, Map<String, Object>> tuple = this.createQuery(); String query = tuple.getValue0(); + if (queryParams.containsKey("as-tree")) { + if (queryParams.getFirst("as-tree").equalsIgnoreCase("true")) { + if (this.isDsl) { // If dsl query and as-tree parameter is true, remove "end" concatenation and append tree. + query = removeDslQueryEnd(query); + } + query = query.concat(".tree()"); // Otherwise, normal gremlin query will just append tree + } + } Map<String, Object> params = tuple.getValue1(); if (query.equals("") && (vertices.isPresent() && vertices.get().isEmpty())) { //nothing to do, just exit return new ArrayList<>(); } - GraphTraversal<?,?> g = this.runQuery(query, params); + GraphTraversal<?,?> g = this.runQuery(query, params, traversalSource); resultVertices = this.processSubGraph(style, g); return resultVertices; } + + private String removeDslQueryEnd(String query) { + String end = ".cap('x').unfold().dedup()"; + if (query.length() <= end.length()) { + return query; + } + if (query.contains(end)) { + int startIndex = query.length() - end.length(); + for (int i = 0; startIndex - i >= 0; i++) { // remove tailing instance + startIndex = query.length() - end.length() - i; + int lastIndex = query.length() - i; + if (query.substring(startIndex, lastIndex).equals(end)) { + query = query.substring(0, startIndex) + query.substring(lastIndex); + break; + } + } + } + return query; + } protected Pair<String, Map<String, Object>> createQuery() throws AAIException { Map<String, Object> params = new HashMap<>(); @@ -128,8 +183,15 @@ public abstract class GenericQueryProcessor { }else if (this.isDsl) { String dslUserQuery = dsl.get(); if(dslQueryProcessorOptional.isPresent()){ - String dslQuery = dslQueryProcessorOptional.get().parseAaiQuery(dslUserQuery); - query = groovyQueryBuilder.executeTraversal(dbEngine, dslQuery, params); + Map<String, Object>resultMap = dslQueryProcessorOptional.get().parseAaiQuery(dslApiVersion, dslUserQuery); + String dslQuery = resultMap.get("query").toString(); + Object propMap = resultMap.get("propertiesMap"); + if (propMap instanceof Map) { + Map<String, List<String>> newPropMap = new HashMap<String, List<String>>(); + newPropMap = (Map<String, List<String>>)propMap; + setPropertiesMap(newPropMap); + } + query = groovyQueryBuilder.executeTraversal(dbEngine, dslQuery, params, style, traversalSource); String startPrefix = "g.V()"; query = startPrefix + query; } @@ -178,7 +240,7 @@ public abstract class GenericQueryProcessor { if (query == null) { query = ""; } else { - query = groovyQueryBuilder.executeTraversal(dbEngine, query, params); + query = groovyQueryBuilder.executeTraversal(dbEngine, query, params, style, traversalSource); } String startPrefix = "g.V(startVertexes)"; @@ -227,7 +289,14 @@ public abstract class GenericQueryProcessor { private GremlinServerSingleton gremlinServerSingleton; private Optional<String> nodeType = Optional.empty(); private boolean isNodeTypeQuery = false; - protected MultivaluedMap<String, String> uriParams; + protected MultivaluedMap<String, String> uriParams; + protected GraphTraversalSource traversalSource; + protected boolean isHistory = false; + protected QueryVersion dslApiVersion; + protected Format format; + + + protected QueryStyle style = QueryStyle.GREMLIN_TRAVERSAL; public Builder(TransactionalGraphEngine dbEngine, GremlinServerSingleton gremlinServerSingleton) { this.dbEngine = dbEngine; @@ -272,11 +341,31 @@ public abstract class GenericQueryProcessor { return this; } + public Builder format(Format format) { + this.format = format; + return this; + } + + public Builder traversalSource(boolean isHistory, GraphTraversalSource source) { + this.traversalSource = source; + this.isHistory = isHistory; + if(this.isHistory){ + this.style = QueryStyle.HISTORY_GREMLIN_TRAVERSAL; + } + + return this; + } + public Builder queryProcessor(DslQueryProcessor dslQueryProcessor){ this.dslQueryProcessor = dslQueryProcessor; return this; } + public Builder version(QueryVersion version){ + this.dslApiVersion = version; + return this; + } + public Optional<DslQueryProcessor> getDslQueryProcessor(){ return Optional.ofNullable(this.dslQueryProcessor); } @@ -288,6 +377,8 @@ public abstract class GenericQueryProcessor { return uri; } + public MultivaluedMap<String, String> getUriParams() { return uriParams; } + public Optional<String> getGremlin() { return gremlin; } @@ -330,6 +421,40 @@ public abstract class GenericQueryProcessor { } return new GroovyShellImpl(this); } + + public GraphTraversalSource getTraversalSource() { + return traversalSource; + } + + public void setTraversalSource(GraphTraversalSource traversalSource) { + this.traversalSource = traversalSource; + } + + public boolean isHistory() { + return isHistory; + } + + public void setHistory(boolean history) { + isHistory = history; + } + + public QueryStyle getStyle() { + return style; + } + + public void setStyle(QueryStyle style) { + this.style = style; + } + + public QueryVersion getDslApiVersion() { + return dslApiVersion; + } + + public void setDslApiVersion(QueryVersion dslApiVersion) { + this.dslApiVersion = dslApiVersion; + } + + public Format getFormat(){ return this.format; } } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java index 9ae3dec..e30f13f 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GremlinServerSingleton.java @@ -21,8 +21,8 @@ package org.onap.aai.rest.search; import org.onap.aai.logging.LogFormatTools; import org.onap.aai.util.AAIConstants; -import org.onap.aai.util.FileWatcher; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import org.apache.tinkerpop.gremlin.driver.Cluster; import org.springframework.beans.factory.annotation.Autowired; @@ -43,7 +43,7 @@ import java.util.TimerTask; public class GremlinServerSingleton { - private static EELFLogger logger = EELFManager.getInstance().getLogger(GremlinServerSingleton.class); + private static Logger logger = LoggerFactory.getLogger(GremlinServerSingleton.class); private boolean timerSet; private Timer timer; diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java index 712d7f0..340c525 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/GroovyShellImpl.java @@ -23,7 +23,13 @@ import java.util.Map; import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.onap.aai.aailog.logs.AaiDBTraversalMetricLog; import org.onap.aai.restcore.search.GremlinGroovyShell; +import org.onap.aai.restcore.util.URITools; +import org.onap.aai.util.AAIConstants; + +import javax.ws.rs.core.MultivaluedHashMap; public class GroovyShellImpl extends GenericQueryProcessor { @@ -32,13 +38,17 @@ public class GroovyShellImpl extends GenericQueryProcessor { } @Override - protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params) { + protected GraphTraversal<?,?> runQuery(String query, Map<String, Object> params, GraphTraversalSource traversalSource) { - params.put("g", this.dbEngine.asAdmin().getTraversalSource()); - + AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + metricLog.pre(uri); + + params.put("g", traversalSource); GremlinGroovyShell shell = new GremlinGroovyShell(); - - return shell.executeTraversal(query, params); + GraphTraversal<?,?> graphTraversal = shell.executeTraversal(query, params); + + metricLog.post(); + return graphTraversal; } } diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java index bcd4c4e..52957d4 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/LocalCQConfig.java @@ -19,11 +19,14 @@ */ package org.onap.aai.rest.search; -import com.att.eelf.configuration.EELFLogger; +import org.onap.aai.exceptions.AAIException; +import org.onap.aai.logging.ErrorLogHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; +import org.onap.aai.aaf.auth.FileWatcher; import org.onap.aai.logging.LogFormatTools; import org.onap.aai.util.AAIConstants; -import org.onap.aai.util.FileWatcher; import org.springframework.beans.factory.annotation.Value; import javax.annotation.PostConstruct; @@ -37,7 +40,7 @@ import java.util.Timer; import java.util.TimerTask; public class LocalCQConfig extends CQConfig { - private static EELFLogger logger = EELFManager.getInstance().getLogger(LocalCQConfig.class); + private static Logger logger = LoggerFactory.getLogger(LocalCQConfig.class); @Value("${schema.queries.location}") private String storedQueriesLocation; @@ -56,7 +59,9 @@ public class LocalCQConfig extends CQConfig { queryConfig = new GetCustomQueryConfig(customQueryConfigJson); } catch (IOException e) { - logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); + AAIException aaiException = new AAIException("AAI_4002", e); + ErrorLogHelper.logException(aaiException); + //logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); } TimerTask task = new FileWatcher(new File(storedQueriesLocation)) { @@ -69,7 +74,9 @@ public class LocalCQConfig extends CQConfig { queryConfig = new GetCustomQueryConfig(customQueryConfigJson); } catch (IOException e) { - logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); + AAIException aaiException = new AAIException("AAI_4002", e); + ErrorLogHelper.logException(aaiException); + //logger.error("Error occurred during the processing of query json file: " + LogFormatTools.getStackTop(e)); } } }; diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java index 4102c52..e590964 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/ModelAndNamedQueryRestProvider.java @@ -19,22 +19,21 @@ */ package org.onap.aai.rest.search; -import com.att.eelf.configuration.EELFLogger; -import com.att.eelf.configuration.EELFManager; +import org.onap.aai.aailog.logs.AaiDBTraversalMetricLog; +import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.dbgraphmap.SearchGraph; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; -import org.onap.aai.extensions.AAIExtensionMap; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.StopWatch; + +import org.onap.aai.rest.util.AAIExtensionMap; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.restcore.RESTAPI; import org.onap.aai.setup.SchemaVersions; import org.onap.aai.util.AAIConstants; import org.onap.aai.util.TraversalConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.onap.aai.concurrent.AaiCallable; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.POST; @@ -43,8 +42,9 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.*; import javax.ws.rs.core.Response.Status; +import java.net.URI; import java.util.ArrayList; -import java.util.concurrent.TimeUnit; +import java.util.Optional; /** * Implements the search subdomain in the REST API. All API calls must include @@ -54,15 +54,13 @@ import java.util.concurrent.TimeUnit; @Path("/search") public class ModelAndNamedQueryRestProvider extends RESTAPI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(ModelAndNamedQueryRestProvider.class); + private static final Logger LOGGER = LoggerFactory.getLogger(ModelAndNamedQueryRestProvider.class); public static final String NAMED_QUERY = "/named-query"; public static final String MODEL_QUERY = "/model"; - public static final String TARGET_ENTITY = "DB"; - private SearchGraph searchGraph; private SchemaVersions schemaVersions; @@ -107,19 +105,12 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { public Response processNamedQueryResponse(@Context HttpHeaders headers, @Context HttpServletRequest req, String queryParameters) { - String methodName = "getNamedQueryResponse"; AAIException ex = null; - Response response = null; - String fromAppId = null; - String transId = null; - double dbTimeMsecs = 0; - String rqstTm = genDate(); - ArrayList<String> templateVars = new ArrayList<String>(); + Response response; + String fromAppId; + String transId; + ArrayList<String> templateVars = new ArrayList<String>(); try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - fromAppId = getFromAppId(headers); transId = getTransId(headers); @@ -127,29 +118,25 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { aaiExtMap.setHttpHeaders(headers); aaiExtMap.setServletRequest(req); aaiExtMap.setApiVersion(schemaVersions.getDefaultVersion().toString()); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); - //only consider header value for search - DBConnectionType type = this.determineConnectionType("force-cache", realTime); - - LoggingContext.startTime(); - StopWatch.conditionalStart(); - - response = searchGraph.runNamedQuery(fromAppId, transId, queryParameters, type, aaiExtMap); - - dbTimeMsecs += StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long)dbTimeMsecs,TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - - - LOGGER.info ("Completed"); - - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); - - String respTm = genDate(); + //only consider header value for search + + + AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + String uriString = req.getRequestURI(); + Optional<URI> o; + if (uriString != null) { + o = Optional.of(new URI(uriString)); + } + else { + o = Optional.empty(); + } + metricLog.pre(o); + + response = searchGraph.runNamedQuery(fromAppId, transId, queryParameters, aaiExtMap); + metricLog.post(); + //LOGGER.info ("Completed"); } catch (AAIException e) { - LoggingContext.restoreIfPossible(); // send error response ex = e; templateVars.add("POST Search"); @@ -159,7 +146,6 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) .build(); } catch (Exception e) { - LoggingContext.restoreIfPossible(); // send error response ex = new AAIException("AAI_4000", e); templateVars.add("POST Search"); @@ -214,20 +200,13 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { @Context HttpServletRequest req, String inboundPayload, @QueryParam("action") String action) { - String methodName = "getModelQueryResponse"; AAIException ex = null; - Response response = null; - String fromAppId = null; - String transId = null; - double dbTimeMsecs = 0; - - String rqstTm = genDate(); - ArrayList<String> templateVars = new ArrayList<String>(); + Response response; + String fromAppId; + String transId; + + ArrayList<String> templateVars = new ArrayList<>(); try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); - fromAppId = getFromAppId(headers); transId = getTransId(headers); @@ -238,30 +217,28 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { aaiExtMap.setFromAppId(fromAppId); aaiExtMap.setTransId(transId); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); - //only consider header value for search - DBConnectionType type = this.determineConnectionType("force-cache", realTime); - - LoggingContext.startTime(); - StopWatch.conditionalStart(); - + //only consider header value for search + + + AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + String uriString = req.getRequestURI(); + Optional<URI> o; + if (uriString != null) { + o = Optional.of(new URI(uriString)); + } + else { + o = Optional.empty(); + } + metricLog.pre(o); if (action != null && action.equalsIgnoreCase("DELETE")) { - response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, type, true, aaiExtMap); + response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, true, aaiExtMap); } else { - response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, type, false, aaiExtMap); + response = searchGraph.executeModelOperation(fromAppId, transId, inboundPayload, false, aaiExtMap); } - dbTimeMsecs += StopWatch.stopIfStarted(); - LoggingContext.elapsedTime((long)dbTimeMsecs,TimeUnit.MILLISECONDS); - LoggingContext.successStatusFields(); - - LOGGER.info ("Completed"); - - LoggingContext.restoreIfPossible(); - LoggingContext.successStatusFields(); - String respTm = genDate(); - + metricLog.post(); + //LOGGER.info ("Completed"); + } catch (AAIException e) { - LoggingContext.restoreIfPossible(); // send error response ex = e; templateVars.add("POST Search"); @@ -271,7 +248,6 @@ public class ModelAndNamedQueryRestProvider extends RESTAPI { .entity(ErrorLogHelper.getRESTAPIErrorResponse(headers.getAcceptableMediaTypes(), e, templateVars)) .build(); } catch (Exception e) { - LoggingContext.restoreIfPossible(); // send error response ex = new AAIException("AAI_4000", e); templateVars.add("POST Search"); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java index 6421f67..61f370b 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/NodeQueryProcessor.java @@ -19,7 +19,8 @@ */ package org.onap.aai.rest.search; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit; @@ -41,7 +42,7 @@ import javax.ws.rs.core.MultivaluedMap; public class NodeQueryProcessor extends GroovyShellImpl { - private static EELFLogger LOGGER = EELFManager.getInstance().getLogger(NodeQueryProcessor.class); + private static Logger LOGGER = LoggerFactory.getLogger(NodeQueryProcessor.class); protected String nodeType; private MultivaluedMap<String, String> nodeQueryParams = new MultivaluedHashMap<String, String>(); @@ -106,7 +107,7 @@ public class NodeQueryProcessor extends GroovyShellImpl { // nothing to do, just exit return new ArrayList<>(); } - GraphTraversal<?, ?> g = this.runQuery(query, params); + GraphTraversal<?, ?> g = this.runQuery(query, params, dbEngine.asAdmin().getTraversalSource()); resultVertices.addAll(g.toList()); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java b/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java index 6e55246..ea1b62f 100644 --- a/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java +++ b/aai-traversal/src/main/java/org/onap/aai/rest/search/SchemaServiceCQConfig.java @@ -19,12 +19,13 @@ */ package org.onap.aai.rest.search; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import org.onap.aai.restclient.RestClient; -import org.onap.aai.restclient.RestClientFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.ResponseEntity; import javax.annotation.PostConstruct; @@ -33,14 +34,15 @@ import java.util.Map; public class SchemaServiceCQConfig extends CQConfig { - private static EELFLogger logger = EELFManager.getInstance().getLogger(SchemaServiceCQConfig.class); + private static Logger logger = LoggerFactory.getLogger(SchemaServiceCQConfig.class); private static final String SCHEMA_SERVICE = "schema-service"; @Value("${schema.service.custom.queries.endpoint}") private String customQueriesUri; + @Qualifier("restClient") @Autowired - private RestClientFactory restClientFactory; + private RestClient restClient; @PostConstruct public void initialize() { @@ -55,8 +57,6 @@ public class SchemaServiceCQConfig extends CQConfig { logger.info("Calling the SchemaService to retrieve stored queries"); String content = ""; Map<String, String> headersMap = new HashMap<>(); - RestClient restClient = restClientFactory - .getRestClient(SCHEMA_SERVICE); ResponseEntity<String> schemaResponse = restClient.getGetRequest(content, customQueriesUri, headersMap); queryConfig = new GetCustomQueryConfig(schemaResponse.getBody()); 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 8c97c0a..75a19c9 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 @@ -19,48 +19,41 @@ */ 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; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -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.aailog.logs.AaiDBTraversalMetricLog; +import org.onap.aai.concurrent.AaiCallable; import org.onap.aai.dbgraphmap.SearchGraph; -import org.onap.aai.dbmap.DBConnectionType; import org.onap.aai.exceptions.AAIException; import org.onap.aai.introspection.Loader; import org.onap.aai.introspection.LoaderFactory; import org.onap.aai.introspection.ModelType; import org.onap.aai.logging.ErrorLogHelper; -import org.onap.aai.logging.LoggingContext; -import org.onap.aai.logging.StopWatch; import org.onap.aai.restcore.HttpMethod; import org.onap.aai.restcore.RESTAPI; import org.onap.aai.serialization.db.DBSerializer; -import org.onap.aai.serialization.engines.QueryStyle; import org.onap.aai.serialization.engines.JanusGraphDBEngine; +import org.onap.aai.serialization.engines.QueryStyle; 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.slf4j.Logger; +import org.slf4j.LoggerFactory; 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; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.*; +import javax.ws.rs.core.Response.Status; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + /** * Implements the search subdomain in the REST API. All API calls must include X-FromAppId and * X-TransactionId in the header. @@ -68,14 +61,12 @@ import org.springframework.beans.factory.annotation.Value; @Path("/{version: v[1-9][0-9]*|latest}/search") public class SearchProvider extends RESTAPI { - private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(SearchProvider.class); + private static final Logger LOGGER = LoggerFactory.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; @@ -130,51 +121,37 @@ public class SearchProvider extends RESTAPI { @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; + Response searchResult; + String fromAppId; + ArrayList<String> templateVars = new ArrayList<>(); try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); fromAppId = getFromAppId(headers); - transId = getTransId(headers); - String realTime = headers.getRequestHeaders().getFirst("Real-Time"); + getTransId(headers); // 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); + TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - LoggingContext.startTime(); - StopWatch.conditionalStart(); + + AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + metricLog.pre(Optional.of(new URI(req.getRequestURI()))); + 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(); + metricLog.post(); - String respTm = genDate(); + //LOGGER.info("Completed"); } catch (AAIException e) { - LoggingContext.restoreIfPossible(); // send error response ex = e; templateVars.add("GET Search"); @@ -183,7 +160,6 @@ public class SearchProvider extends RESTAPI { .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"); @@ -239,50 +215,37 @@ public class SearchProvider extends RESTAPI { @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; + Response searchResult; + String fromAppId; + ArrayList<String> templateVars = new ArrayList<>(); try { - LoggingContext.save(); - LoggingContext.targetEntity(TARGET_ENTITY); - LoggingContext.targetServiceName(methodName); fromAppId = getFromAppId(headers); - transId = getTransId(headers); + 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); + TransactionalGraphEngine dbEngine = new JanusGraphDBEngine(QueryStyle.TRAVERSAL, loader); DBSerializer dbSerializer = new DBSerializer(version, dbEngine, factoryType, fromAppId); UrlBuilder urlBuilder = new UrlBuilder(version, dbSerializer, schemaVersions, this.basePath); - LoggingContext.startTime(); - StopWatch.conditionalStart(); + + AaiDBTraversalMetricLog metricLog = new AaiDBTraversalMetricLog (AAIConstants.AAI_TRAVERSAL_MS); + metricLog.pre(Optional.of(new URI(req.getRequestURI()))); 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(); + metricLog.post(); + //LOGGER.info("Completed"); - String respTm = genDate(); } catch (AAIException e) { - LoggingContext.restoreIfPossible(); // send error response ex = e; templateVars.add("GET Search"); @@ -291,7 +254,6 @@ public class SearchProvider extends RESTAPI { .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"); diff --git a/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java b/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java new file mode 100644 index 0000000..0aa70e3 --- /dev/null +++ b/aai-traversal/src/main/java/org/onap/aai/rest/util/AAIExtensionMap.java @@ -0,0 +1,826 @@ +/** + * ============LICENSE_START======================================================= + * org.onap.aai + * ================================================================================ + * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.aai.rest.util; + +import org.apache.tinkerpop.gremlin.structure.Graph; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; +import org.onap.aai.domain.responseMessage.AAIResponseMessages; +import org.onap.aai.introspection.Loader; +import org.onap.aai.rest.db.DBRequest; +import org.onap.aai.rest.db.HttpEntry; +import org.onap.aai.serialization.engines.TransactionalGraphEngine; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.UriInfo; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; + +public class AAIExtensionMap { + // ======================================================================= + // Attribute | Type + // ======================================================================= + // message | java.lang.String (RW) + // ---------------------------------------------------------------------- + // templateVars | java.lang.ArrayList<String> (RW) + // ----------------------------------------------------------------------- + // preExtException | java.lang.Exception (RW) + // ----------------------------------------------------------------------- + // preExtErrorCallback | java.lang.reflect.Method (RW) + // ----------------------------------------------------------------------- + // postExtException | java.lang.Exception (RW) + // ----------------------------------------------------------------------- + // postExtErrorCallback | java.lang.reflect.Method (RW) + // ----------------------------------------------------------------------- + // servletRequest | javax.servlet.http.HttpServletRequest (RO) + // ----------------------------------------------------------------------- + // headers | javax.ws.rs.core.HttpHeaders (RO) + // ----------------------------------------------------------------------- + // objFromRequestType | String (ex. ?org.onap.aai.domain.yang.Vce?) (RO) + // ----------------------------------------------------------------------- + // objFromRequest | $TYPE {ObjFromRequestType) (RO) + // ----------------------------------------------------------------------- + // preExtFailOnError | java.lang.Boolean (RW) + // ----------------------------------------------------------------------- + // postExtFailOnError | java.lang.Boolean (RW) + // ----------------------------------------------------------------------- + // preExtSkipErrorCallback | java.lang.Boolean (RW) + // ----------------------------------------------------------------------- + // postExtSkipErrorCallback | java.lang.Boolean (RW) + // ----------------------------------------------------------------------- + // graph | org.janusgraph.core.JanusGraph (RW) + // ----------------------------------------------------------------------- + // objectFromResponse | Object + // ----------------------------------------------------------------------- + // precheckAddedList | java.util.HashMap + // ----------------------------------------------------------------------- + // precheckResponseMessages | org.onap.aai.extensions.AAIResponseMessages + // ======================================================================= + + private String message; + private ArrayList<String> templateVars; + private Exception preExtException; + private Exception postExtException; + private Method preExtErrorCallback; + private Method postExtErrorCallback; + private HttpServletRequest servletRequest; + private HttpHeaders httpHeaders; + private String objectFromRequestType; + private Object objectFromRequest; + private boolean preExtFailOnError = true; + private boolean postExtFailOnError = true; + private boolean preExtSkipErrorCallback = true; + private boolean postExtSkipErrorCallback = true; + private String fromAppId; + private String transId; + private Graph graph; + private Object objectFromResponse; + private HashMap<String, Object> lookupHashMap; + private HashMap<String, ArrayList<String>> precheckAddedList; + private AAIResponseMessages precheckResponseMessages; + private HashMap<String, Object> topology; + private HashMap<String, Vertex> vertexCache; + private String baseObject; + private String namespace; + private String fullResourceName; + private String topObjectFullResourceName; + private String uri; + private String notificationUri; + private String apiVersion; + private long startTime; + private long checkpointTime; + private DynamicJAXBContext jaxbContext; + private String objectFromResponseType; + private String eventAction; + private TransactionalGraphEngine dbEngine; + private Loader loader; + private UriInfo uriInfo; + private DBRequest dbRequest; + private HttpEntry httpEntry; + + /** + * Sets the message. + * + * @param _message the new message + */ + public void setMessage(String _message) { + this.message = _message; + } + + /** + * Sets the template vars. + * + * @param _templateVars the new template vars + */ + public void setTemplateVars(ArrayList<String> _templateVars) { + this.templateVars = _templateVars; + } + + /** + * Sets the pre ext exception. + * + * @param _exception the new pre ext exception + */ + public void setPreExtException(Exception _exception) { + this.preExtException = _exception; + } + + /** + * Sets the pre ext error callback. + * + * @param _errorCallback the new pre ext error callback + */ + public void setPreExtErrorCallback(Method _errorCallback) { + this.preExtErrorCallback = _errorCallback; + } + + /** + * Sets the post ext exception. + * + * @param _exception the new post ext exception + */ + public void setPostExtException(Exception _exception) { + this.postExtException = _exception; + } + + /** + * Sets the post ext error callback. + * + * @param _errorCallback the new post ext error callback + */ + public void setPostExtErrorCallback(Method _errorCallback) { + this.postExtErrorCallback = _errorCallback; + } + + /** + * Sets the servlet request. + * + * @param _httpServletRequest the new servlet request + */ + public void setServletRequest(HttpServletRequest _httpServletRequest) { + this.servletRequest = _httpServletRequest; + } + + /** + * Sets the http headers. + * + * @param _httpHeaders the new http headers + */ + public void setHttpHeaders(HttpHeaders _httpHeaders) { + this.httpHeaders = _httpHeaders; + } + + /** + * Sets the object from request type. + * + * @param _objectFromRequestType the new object from request type + */ + public void setObjectFromRequestType(String _objectFromRequestType) { + this.objectFromRequestType = _objectFromRequestType; + } + + /** + * Sets the object from request. + * + * @param _objectFromRequest the new object from request + */ + public void setObjectFromRequest(Object _objectFromRequest) { + this.objectFromRequest = _objectFromRequest; + } + + /** + * Sets the object from response type. + * + * @param resourceClassName the new object from response type + */ + public void setObjectFromResponseType(String resourceClassName) { + // TODO Auto-generated method stub + this.objectFromResponseType = resourceClassName; + } + + /** + * Gets the object from response type. + * + * @return the object from response type + */ + public String getObjectFromResponseType() { + // TODO Auto-generated method stub + return this.objectFromResponseType; + } + + /** + * Sets the pre ext fail on error. + * + * @param _failOnError the new pre ext fail on error + */ + public void setPreExtFailOnError(boolean _failOnError) { + this.preExtFailOnError = _failOnError; + } + + /** + * Sets the post ext fail on error. + * + * @param _failOnError the new post ext fail on error + */ + public void setPostExtFailOnError(boolean _failOnError) { + this.postExtFailOnError = _failOnError; + } + + /** + * Gets the message. + * + * @return the message + */ + public String getMessage() { + return this.message; + } + + /** + * Gets the template vars. + * + * @return the template vars + */ + public ArrayList<String> getTemplateVars() { + if (this.templateVars == null) { + this.templateVars = new ArrayList<String>(); + } + return this.templateVars; + } + + /** + * Gets the pre ext exception. + * + * @return the pre ext exception + */ + public Exception getPreExtException() { + return this.preExtException; + } + + /** + * Gets the pre ext error callback. + * + * @return the pre ext error callback + */ + public Method getPreExtErrorCallback() { + return this.preExtErrorCallback; + } + + /** + * Gets the post ext exception. + * + * @return the post ext exception + */ + public Exception getPostExtException() { + return this.postExtException; + } + + /** + * Gets the post ext error callback. + * + * @return the post ext error callback + */ + public Method getPostExtErrorCallback() { + return this.postExtErrorCallback; + } + + /** + * Gets the http servlet request. + * + * @return the http servlet request + */ + public HttpServletRequest getHttpServletRequest() { + return this.servletRequest; + } + + /** + * Gets the http headers. + * + * @return the http headers + */ + public HttpHeaders getHttpHeaders() { + return this.httpHeaders; + } + + /** + * Gets the object from request type. + * + * @return the object from request type + */ + public String getObjectFromRequestType() { + return this.objectFromRequestType; + } + + /** + * Gets the object from request. + * + * @return the object from request + */ + public Object getObjectFromRequest() { + return this.objectFromRequest; + } + + /** + * Gets the pre ext fail on error. + * + * @return the pre ext fail on error + */ + public boolean getPreExtFailOnError() { + return this.preExtFailOnError; + } + + /** + * Gets the post ext fail on error. + * + * @return the post ext fail on error + */ + public boolean getPostExtFailOnError() { + return this.postExtFailOnError; + } + + /** + * Gets the from app id. + * + * @return the from app id + */ + public String getFromAppId() { + return this.fromAppId; + } + + /** + * Sets the from app id. + * + * @param fromAppId the new from app id + */ + public void setFromAppId(String fromAppId) { + this.fromAppId = fromAppId; + } + + /** + * Gets the trans id. + * + * @return the trans id + */ + public String getTransId() { + return this.transId; + } + + /** + * Sets the trans id. + * + * @param transId the new trans id + */ + public void setTransId(String transId) { + this.transId = transId; + } + + /** + * Gets the pre ext skip error callback. + * + * @return the pre ext skip error callback + */ + public boolean getPreExtSkipErrorCallback() { + return preExtSkipErrorCallback; + } + + /** + * Sets the pre ext skip error callback. + * + * @param preExtSkipErrorCallback the new pre ext skip error callback + */ + public void setPreExtSkipErrorCallback(boolean preExtSkipErrorCallback) { + this.preExtSkipErrorCallback = preExtSkipErrorCallback; + } + + /** + * Gets the post ext skip error callback. + * + * @return the post ext skip error callback + */ + public boolean getPostExtSkipErrorCallback() { + return postExtSkipErrorCallback; + } + + /** + * Sets the post ext skip error callback. + * + * @param postExtSkipErrorCallback the new post ext skip error callback + */ + public void setPostExtSkipErrorCallback(boolean postExtSkipErrorCallback) { + this.postExtSkipErrorCallback = postExtSkipErrorCallback; + } + + /** + * Gets the graph. + * + * @return the graph + */ + public Graph getGraph() { + return graph; + } + + /** + * Sets the graph. + * + * @param graph the new graph + */ + public void setGraph(Graph graph) { + this.graph = graph; + } + + /** + * Gets the object from response. + * + * @return the object from response + */ + public Object getObjectFromResponse() { + return objectFromResponse; + } + + /** + * Sets the object from response. + * + * @param objectFromResponse the new object from response + */ + public void setObjectFromResponse(Object objectFromResponse) { + this.objectFromResponse = objectFromResponse; + } + + /** + * Gets the lookup hash map. + * + * @return the lookup hash map + */ + public HashMap<String, Object> getLookupHashMap() { + if (this.lookupHashMap == null) { + this.lookupHashMap = new HashMap<String, Object>(); + } + return this.lookupHashMap; + } + + /** + * Sets the lookup hash map. + * + * @param lookupHashMap the lookup hash map + */ + public void setLookupHashMap(HashMap<String, Object> lookupHashMap) { + this.lookupHashMap = lookupHashMap; + } + + /** + * Gets the precheck added list. + * + * @return the precheck added list + */ + public HashMap<String, ArrayList<String>> getPrecheckAddedList() { + if (this.precheckAddedList == null) { + this.precheckAddedList = new HashMap<String, ArrayList<String>>(); + } + return precheckAddedList; + } + + /** + * Sets the precheck added list. + * + * @param precheckAddedList the precheck added list + */ + public void setPrecheckAddedList(HashMap<String, ArrayList<String>> precheckAddedList) { + this.precheckAddedList = precheckAddedList; + } + + /** + * Gets the precheck response messages. + * + * @return the precheck response messages + */ + public AAIResponseMessages getPrecheckResponseMessages() { + if (this.precheckResponseMessages == null) { + this.precheckResponseMessages = new AAIResponseMessages(); + } + return precheckResponseMessages; + } + + /** + * Sets the precheck response messages. + * + * @param precheckResponseData the new precheck response messages + */ + public void setPrecheckResponseMessages(AAIResponseMessages precheckResponseData) { + this.precheckResponseMessages = precheckResponseData; + } + + /** + * Gets the topology. + * + * @return the topology + */ + public HashMap<String, Object> getTopology() { + if (this.topology == null) { + this.topology = new HashMap<String, Object>(); + } + return topology; + } + + /** + * Gets the vertex cache. + * + * @return the vertex cache + */ + public HashMap<String, Vertex> getVertexCache() { + if (this.vertexCache == null) { + this.vertexCache = new HashMap<String, Vertex>(); + } + return vertexCache; + } + + /** + * Gets the base object. + * + * @return the base object + */ + public String getBaseObject() { + return baseObject; + } + + /** + * Sets the base object. + * + * @param baseObject the new base object + */ + public void setBaseObject(String baseObject) { + this.baseObject = baseObject; + } + + /** + * Gets the namespace. + * + * @return the namespace + */ + public String getNamespace() { + return namespace; + } + + /** + * Sets the namespace. + * + * @param namespace the new namespace + */ + public void setNamespace(String namespace) { + this.namespace = namespace; + } + + /** + * Gets the full resource name. + * + * @return the full resource name + */ + public String getFullResourceName() { + return fullResourceName; + } + + /** + * Sets the full resource name. + * + * @param fullResourceName the new full resource name + */ + public void setFullResourceName(String fullResourceName) { + this.fullResourceName = fullResourceName; + } + + /** + * Gets the top object full resource name. + * + * @return the top object full resource name + */ + public String getTopObjectFullResourceName() { + return topObjectFullResourceName; + } + + /** + * Sets the top object full resource name. + * + * @param topObjectFullResourceName the new top object full resource name + */ + public void setTopObjectFullResourceName(String topObjectFullResourceName) { + this.topObjectFullResourceName = topObjectFullResourceName; + } + + /** + * Gets the uri. + * + * @return the uri + */ + public String getUri() { + return uri; + } + + /** + * Sets the uri. + * + * @param uri the new uri + */ + public void setUri(String uri) { + this.uri = uri; + } + + /** + * Gets the api version. + * + * @return the api version + */ + public String getApiVersion() { + return apiVersion; + } + + /** + * Sets the api version. + * + * @param apiVersion the new api version + */ + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + /** + * Sets the notification uri. + * + * @param uri the new notification uri + */ + public void setNotificationUri(String uri) { + this.notificationUri = uri; + + } + + /** + * Gets the notification uri. + * + * @return the notification uri + */ + public String getNotificationUri() { + return this.notificationUri; + + } + + /** + * Gets the start time. + * + * @return the start time + */ + public long getStartTime() { + return startTime; + } + + /** + * Sets the start time. + * + * @param startTime the new start time + */ + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + /** + * Gets the checkpoint time. + * + * @return the checkpoint time + */ + public long getCheckpointTime() { + return checkpointTime; + } + + /** + * Sets the checkpoint time. + * + * @param checkpointTime the new checkpoint time + */ + public void setCheckpointTime(long checkpointTime) { + this.checkpointTime = checkpointTime; + } + + /** + * Gets the jaxb context. + * + * @return the jaxb context + */ + public DynamicJAXBContext getJaxbContext() { + return jaxbContext; + } + + /** + * Sets the jaxb context. + * + * @param jaxbContext the new jaxb context + */ + public void setJaxbContext(DynamicJAXBContext jaxbContext) { + this.jaxbContext = jaxbContext; + } + + /** + * Sets the event action. + * + * @param eventAction the new event action + */ + public void setEventAction(String eventAction) { + this.eventAction = eventAction; + } + + /** + * Gets the event action. + * + * @return the event action + */ + public String getEventAction() { + return this.eventAction; + } + + /** + * Gets the transactional graph engine. + * + * @return the transactional graph engine + */ + public TransactionalGraphEngine getTransactionalGraphEngine() { + return this.dbEngine; + + } + + /** + * Sets the transactional graph engine. + * + * @param dbEngine the new transactional graph engine + */ + public void setTransactionalGraphEngine(TransactionalGraphEngine dbEngine) { + this.dbEngine = dbEngine; + + } + + /** + * Gets the loader. + * + * @return the loader + */ + public Loader getLoader() { + return loader; + } + + /** + * Sets the loader. + * + * @param loader the new loader + */ + public void setLoader(Loader loader) { + this.loader = loader; + } + + /** + * Gets the uri info. + * + * @return the uri info + */ + public UriInfo getUriInfo() { + return uriInfo; + } + + /** + * Sets the uri info. + * + * @param uriInfo the new uri info + */ + public void setUriInfo(UriInfo uriInfo) { + this.uriInfo = uriInfo; + } + + public DBRequest getDbRequest() { + return dbRequest; + } + + public void setDbRequest(DBRequest dbRequest) { + this.dbRequest = dbRequest; + } + + public HttpEntry getHttpEntry() { + return httpEntry; + } + + public void setHttpEntry(HttpEntry httpEntry) { + this.httpEntry = httpEntry; + } +} diff --git a/aai-traversal/src/main/java/org/onap/aai/service/AuthorizationService.java b/aai-traversal/src/main/java/org/onap/aai/service/AuthorizationService.java index 2bb2794..c0fa93e 100644 --- a/aai-traversal/src/main/java/org/onap/aai/service/AuthorizationService.java +++ b/aai-traversal/src/main/java/org/onap/aai/service/AuthorizationService.java @@ -19,7 +19,8 @@ */ package org.onap.aai.service; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import org.eclipse.jetty.util.security.Password; import org.onap.aai.Profiles; @@ -41,7 +42,7 @@ import java.util.stream.Stream; @Profile(Profiles.ONE_WAY_SSL) public class AuthorizationService { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(AuthorizationService.class); + private static final Logger logger = LoggerFactory.getLogger(AuthorizationService.class); private final Map<String, String> authorizedUsers = new HashMap<>(); @@ -72,7 +73,7 @@ public class AuthorizationService { String[] usernamePasswordArray = usernamePassword.split(":"); if(usernamePasswordArray == null || usernamePasswordArray.length != 3){ - throw new RuntimeException("Not a valid entry for the realm.properties entry: " + usernamePassword); + throw new RuntimeException("This username / pwd is not a valid entry in realm.properties"); } String username = usernamePasswordArray[0]; diff --git a/aai-traversal/src/main/java/org/onap/aai/transforms/MapTraverser.java b/aai-traversal/src/main/java/org/onap/aai/transforms/MapTraverser.java index 36c453a..9091998 100644 --- a/aai-traversal/src/main/java/org/onap/aai/transforms/MapTraverser.java +++ b/aai-traversal/src/main/java/org/onap/aai/transforms/MapTraverser.java @@ -19,13 +19,14 @@ */ package org.onap.aai.transforms; + +import joptsimple.internal.Objects; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.commons.collections.MapUtils; - public class MapTraverser { private Converter converter; @@ -36,9 +37,8 @@ public class MapTraverser { public Map<String, Object> convertKeys(Map<String, Object> map){ - if (MapUtils.isEmpty(map)) { - throw new NullPointerException("map cannot be null"); - } + Objects.ensureNotNull(map); + Map<String, Object> modifiedMap = new HashMap<String, Object>(); convertKeys(map, modifiedMap); diff --git a/aai-traversal/src/main/java/org/onap/aai/util/MakeNamedQuery.java b/aai-traversal/src/main/java/org/onap/aai/util/MakeNamedQuery.java index 503cf6c..4a80f58 100644 --- a/aai-traversal/src/main/java/org/onap/aai/util/MakeNamedQuery.java +++ b/aai-traversal/src/main/java/org/onap/aai/util/MakeNamedQuery.java @@ -26,7 +26,8 @@ import java.util.List; import java.util.Map.Entry; import java.util.UUID; -import com.att.eelf.configuration.EELFLogger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.att.eelf.configuration.EELFManager; import org.apache.commons.io.FileUtils; import org.onap.aai.config.SpringContextAware; @@ -41,7 +42,7 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext public class MakeNamedQuery { - private static final EELFLogger logger = EELFManager.getInstance().getLogger(MakeNamedQuery.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(MakeNamedQuery.class.getName()); public static void main(String[] args) throws Exception { String _apiVersion = AAIConfig.get(AAIConstants.AAI_DEFAULT_API_VERSION_PROP); diff --git a/aai-traversal/src/main/java/org/onap/aai/util/TraversalConstants.java b/aai-traversal/src/main/java/org/onap/aai/util/TraversalConstants.java index 4b5ebfe..fdeefe1 100644 --- a/aai-traversal/src/main/java/org/onap/aai/util/TraversalConstants.java +++ b/aai-traversal/src/main/java/org/onap/aai/util/TraversalConstants.java @@ -31,7 +31,8 @@ public final class TraversalConstants { public static final String AAI_TRAVERSAL_DSL_TIMEOUT_APP = "aai.traversal.dsl.timeout.appspecific"; public static final String DSL_NOVALIDATION_CLIENTS = "aai.traversal.dsl.novalidation.clients"; public static final String DSL_OVERRIDE = "aai.dsl.override"; - + public static final String DSL_MAX_NODE_COUNT = "15"; + public static final long HISTORY_MAX_HOURS = 192; private TraversalConstants() { diff --git a/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java b/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java index ab3c9fd..e6cf080 100644 --- a/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java +++ b/aai-traversal/src/main/java/org/onap/aai/web/JerseyConfiguration.java @@ -19,131 +19,131 @@ */ package org.onap.aai.web; +import jersey.repackaged.com.google.common.collect.Sets; import org.glassfish.jersey.filter.LoggingFilter; import org.glassfish.jersey.server.ResourceConfig; -import org.glassfish.jersey.servlet.ServletProperties; -import org.onap.aai.rest.CQ2Gremlin; -import org.onap.aai.rest.CQ2GremlinTest; -import org.onap.aai.rest.DslConsumer; -import org.onap.aai.rest.QueryConsumer; -import org.onap.aai.rest.RecentAPIConsumer; +import org.onap.aai.aailog.logs.AaiDebugLog; +import org.onap.aai.rest.*; import org.onap.aai.rest.search.ModelAndNamedQueryRestProvider; import org.onap.aai.rest.search.SearchProvider; import org.onap.aai.rest.util.EchoResponse; -import org.reflections.Reflections; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; import javax.annotation.Priority; -import javax.ws.rs.container.ContainerRequestFilter; -import javax.ws.rs.container.ContainerResponseFilter; - -import java.util.List; +import java.lang.reflect.AnnotatedElement; +import java.util.Collection; +import java.util.Comparator; import java.util.Set; import java.util.logging.Logger; -import java.util.stream.Collectors; -@Component -public class JerseyConfiguration extends ResourceConfig { +import static java.lang.Boolean.parseBoolean; +import static java.util.Comparator.comparingInt; - private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName()); +@Configuration +public class JerseyConfiguration { - private Environment env; + private static final Logger log = Logger.getLogger(JerseyConfiguration.class.getName()); + private static final org.slf4j.Logger logger = LoggerFactory.getLogger(JerseyConfiguration.class.getName()); - @Autowired - public JerseyConfiguration(Environment env) { - - this.env = env; - - register(SearchProvider.class); - register(ModelAndNamedQueryRestProvider.class); - register(QueryConsumer.class); - register(RecentAPIConsumer.class); - register(DslConsumer.class); - register(EchoResponse.class); - register(CQ2Gremlin.class); - register(CQ2GremlinTest.class); - - //Request Filters - registerFiltersForRequests(); - // Response Filters - registerFiltersForResponses(); - - property(ServletProperties.FILTER_FORWARD_ON_404, true); - - // Following registers the request headers and response headers - // If the LoggingFilter second argument is set to true, it will print response value as well - if ("true".equalsIgnoreCase(env.getProperty("aai.request.logging.enabled"))) { - register(new LoggingFilter(log, false)); - } + private static AaiDebugLog debugLog = new AaiDebugLog(); + static { + debugLog.setupMDC(); } - public void registerFiltersForRequests() { + private static final String LOGGING_ENABLED_PROPERTY = "aai.request.logging.enabled"; + private static final boolean ENABLE_RESPONSE_LOGGING = false; + + private final Environment environment; - // Find all the classes within the interceptors package - Reflections reflections = new Reflections("org.onap.aai.interceptors"); - // Filter them based on the clazz that was passed in - Set<Class<? extends ContainerRequestFilter>> filters = reflections.getSubTypesOf(ContainerRequestFilter.class); + @Autowired + public JerseyConfiguration(Environment environment) { + this.environment = environment; + } + @Bean + public ResourceConfig resourceConfig() { + ResourceConfig resourceConfig = new ResourceConfig(); + + Set<Class<?>> classes = Sets.newHashSet( + SearchProvider.class, + ModelAndNamedQueryRestProvider.class, + QueryConsumer.class, + RecentAPIConsumer.class, + DslConsumer.class, + EchoResponse.class, + CQ2Gremlin.class, + CQ2GremlinTest.class + ); + Set<Class<?>> filterClasses = Sets.newHashSet( + org.onap.aai.aailog.filter.AaiAuditLogContainerFilter.class, + org.onap.aai.interceptors.pre.RequestTransactionLogging.class, + org.onap.aai.interceptors.pre.HeaderValidation.class, + org.onap.aai.interceptors.pre.HttpHeaderInterceptor.class, + org.onap.aai.interceptors.pre.OneWaySslAuthorization.class, + org.onap.aai.interceptors.pre.VersionLatestInterceptor.class, + org.onap.aai.interceptors.pre.RetiredInterceptor.class, + org.onap.aai.interceptors.pre.VersionInterceptor.class, + org.onap.aai.interceptors.pre.RequestHeaderManipulation.class, + org.onap.aai.interceptors.pre.RequestModification.class, + org.onap.aai.interceptors.post.InvalidResponseStatus.class, + org.onap.aai.interceptors.post.ResponseTransactionLogging.class, + org.onap.aai.interceptors.post.ResponseHeaderManipulation.class + ); + if (isLoggingEnabled()) { + logRequests(resourceConfig); + } + resourceConfig.registerClasses(classes); + logger.debug("REGISTERED CLASSES " + classes.toString()); + + throwIfPriorityAnnotationAbsent(filterClasses); + filterClasses.stream() + .filter(this::isEnabledByActiveProfiles) + .sorted(priorityComparator()) + .forEach(resourceConfig::register); + + filterClasses.stream() + .filter(this::isEnabledByActiveProfiles) + .sorted(priorityComparator()) + .forEach(s -> logger.debug("REGISTERED FILTERS " + s.getName())); + return resourceConfig; + } - // Check to ensure that each of the filter has the @Priority annotation and if not throw exception - for (Class filterClass : filters) { - if (filterClass.getAnnotation(Priority.class) == null) { - throw new RuntimeException("Container filter " + filterClass.getName() + " does not have @Priority annotation"); + private <T> void throwIfPriorityAnnotationAbsent(Collection<Class<? extends T>> classes) { + for (Class clazz : classes) { + if (!clazz.isAnnotationPresent(Priority.class)) { + logger.debug("throwIfPriorityAnnotationAbsent: missing filter priority for : " + clazz.getName()); + throw new MissingFilterPriorityException(clazz); } } + } - // Turn the set back into a list - List<Class<? extends ContainerRequestFilter>> filtersList = filters - .stream() - .filter(f -> { - if (f.isAnnotationPresent(Profile.class) - && !env.acceptsProfiles(f.getAnnotation(Profile.class).value())) { - return false; - } - return true; - }) - .collect(Collectors.toList()); - - // Sort them by their priority levels value - filtersList.sort((c1, c2) -> Integer.valueOf(c1.getAnnotation(Priority.class).value()).compareTo(c2.getAnnotation(Priority.class).value())); - - // Then register this to the jersey application - filtersList.forEach(this::register); + private <T> Comparator<Class<? extends T>> priorityComparator() { + return comparingInt(clazz -> clazz.getAnnotation(Priority.class).value()); } - public void registerFiltersForResponses() { + private void logRequests(ResourceConfig resourceConfig) { + resourceConfig.register(new LoggingFilter(log, ENABLE_RESPONSE_LOGGING)); + } - // Find all the classes within the interceptors package - Reflections reflections = new Reflections("org.onap.aai.interceptors"); - // Filter them based on the clazz that was passed in - Set<Class<? extends ContainerResponseFilter>> filters = reflections.getSubTypesOf(ContainerResponseFilter.class); + private boolean isLoggingEnabled() { + return parseBoolean(environment.getProperty(LOGGING_ENABLED_PROPERTY)); + } + private boolean isEnabledByActiveProfiles(AnnotatedElement annotatedElement) { + boolean result = !annotatedElement.isAnnotationPresent(Profile.class) || + environment.acceptsProfiles(annotatedElement.getAnnotation(Profile.class).value()); + logger.debug("isEnabledByActiveProfiles: annotatedElement: " + annotatedElement.toString() + " result=" + result); + return result; + } - // Check to ensure that each of the filter has the @Priority annotation and if not throw exception - for (Class filterClass : filters) { - if (filterClass.getAnnotation(Priority.class) == null) { - throw new RuntimeException("Container filter " + filterClass.getName() + " does not have @Priority annotation"); - } + private class MissingFilterPriorityException extends RuntimeException { + private MissingFilterPriorityException(Class<?> clazz) { + super("Container filter " + clazz.getName() + " does not have @Priority annotation"); } - - // Turn the set back into a list - List<Class<? extends ContainerResponseFilter>> filtersList = filters.stream() - .filter(f -> { - if (f.isAnnotationPresent(Profile.class) - && !env.acceptsProfiles(f.getAnnotation(Profile.class).value())) { - return false; - } - return true; - }) - .collect(Collectors.toList()); - - // Sort them by their priority levels value - filtersList.sort((c1, c2) -> Integer.valueOf(c1.getAnnotation(Priority.class).value()).compareTo(c2.getAnnotation(Priority.class).value())); - - // Then register this to the jersey application - filtersList.forEach(this::register); } -} +}
\ No newline at end of file |