Skip to content

Instantly share code, notes, and snippets.

@wittling
Created October 17, 2017 15:01
Show Gist options
  • Save wittling/77fcca1978e9a6f6abaf40b831b62b1f to your computer and use it in GitHub Desktop.
Save wittling/77fcca1978e9a6f6abaf40b831b62b1f to your computer and use it in GitHub Desktop.
RestRequest.java with modifications to getAccessToken
2017-10-16 19:24:29.449 INFO 7367 --- [main] o.openbaton.faultmanagement.Application : Starting Application on ubuntu-openbaton with PID 7367 (/opt/openbaton/fm-system/build/libs/fm-system-1.2.6-SNAPSHOT.jar started by root in /opt/openbaton/fm-system)
2017-10-16 19:24:29.452 DEBUG 7367 --- [main] o.openbaton.faultmanagement.Application : Running with Spring Boot v1.5.6.RELEASE, Spring v4.3.10.RELEASE
2017-10-16 19:24:29.453 INFO 7367 --- [main] o.openbaton.faultmanagement.Application : No active profile set, falling back to default profiles: default
2017-10-16 19:24:29.540 INFO 7367 --- [main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@28c97a5: startup date [Mon Oct 16 19:24:29 EDT 2017]; root of context hierarchy
2017-10-16 19:24:30.854 INFO 7367 --- [main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration' of type [org.springframework.amqp.rabbit.annotation.RabbitBootstrapConfiguration$$EnhancerBySpringCGLIB$$ec86a823] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-10-16 19:24:31.238 INFO 7367 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 9000 (http)
2017-10-16 19:24:31.252 INFO 7367 --- [main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2017-10-16 19:24:31.253 INFO 7367 --- [main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.16
2017-10-16 19:24:31.343 INFO 7367 --- [localhost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2017-10-16 19:24:31.343 INFO 7367 --- [localhost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1807 ms
2017-10-16 19:24:31.489 INFO 7367 --- [localhost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2017-10-16 19:24:31.493 INFO 7367 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-10-16 19:24:31.494 INFO 7367 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-10-16 19:24:31.494 INFO 7367 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-10-16 19:24:31.494 INFO 7367 --- [localhost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2017-10-16 19:24:31.841 INFO 7367 --- [main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2017-10-16 19:24:31.857 INFO 7367 --- [main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2017-10-16 19:24:31.932 INFO 7367 --- [main] org.hibernate.Version : HHH000412: Hibernate Core {5.0.12.Final}
2017-10-16 19:24:31.933 INFO 7367 --- [main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2017-10-16 19:24:31.935 INFO 7367 --- [main] org.hibernate.cfg.Environment : HHH000021: Bytecode provider name : javassist
2017-10-16 19:24:31.979 INFO 7367 --- [main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-10-16 19:24:32.142 INFO 7367 --- [main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2017-10-16 19:24:32.637 INFO 7367 --- [main] org.hibernate.tool.hbm2ddl.SchemaUpdate : HHH000228: Running hbm2ddl schema update
2017-10-16 19:24:32.704 INFO 7367 --- [main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: alarm
2017-10-16 19:24:32.705 INFO 7367 --- [main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: alarm
2017-10-16 19:24:32.763 INFO 7367 --- [main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2017-10-16 19:24:33.043 DEBUG 7367 --- [main] o.o.f.core.fc.DroolsAutoConfiguration : Rule: fault_resolution.drl
2017-10-16 19:24:33.055 DEBUG 7367 --- [main] o.o.f.core.fc.DroolsAutoConfiguration : Rule: pre_rules.drl
2017-10-16 19:24:33.056 DEBUG 7367 --- [main] o.o.f.core.fc.DroolsAutoConfiguration : Rule: vnfm_fault_correlator.drl
2017-10-16 19:24:35.034 INFO 7367 --- [main] o.d.c.k.builder.impl.KieRepositoryImpl : KieModule was added: MemoryKieModule[releaseId=org.default:artifact:1.0.0-SNAPSHOT]
2017-10-16 19:24:35.434 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created ConnectionFactory
2017-10-16 19:24:35.462 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Topic Exchange
2017-10-16 19:24:35.466 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Queue for NSR Create event
2017-10-16 19:24:35.468 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Queue for VNF events
2017-10-16 19:24:35.468 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Queue for NSR Delete Event
2017-10-16 19:24:35.470 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Binding for NSR Creation event
2017-10-16 19:24:35.473 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Binding for VNF events
2017-10-16 19:24:35.474 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created Binding for NSR Deletion event
2017-10-16 19:24:35.486 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created MessageContainer for NSR Creation event
2017-10-16 19:24:35.508 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created MessageContainer for VNF events
2017-10-16 19:24:35.510 DEBUG 7367 --- [main] uration$$EnhancerBySpringCGLIB$$8eaa2582 : Created MessageContainer for NSR Deletion event
2017-10-16 19:24:35.734 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@28c97a5: startup date [Mon Oct 16 19:24:29 EDT 2017]; root of context hierarchy
2017-10-16 19:24:35.796 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alarm/vnf],methods=[POST],consumes=[application/json],produces=[application/json]}" onto public org.openbaton.catalogue.mano.common.monitoring.Alarm org.openbaton.faultmanagement.receivers.RestEventReceiver.receiveVnfNewAlarm(org.openbaton.catalogue.mano.common.faultmanagement.VNFAlarmNotification)
2017-10-16 19:24:35.797 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alarm/vnf],methods=[PUT],consumes=[application/json],produces=[application/json]}" onto public org.openbaton.catalogue.mano.common.monitoring.Alarm org.openbaton.faultmanagement.receivers.RestEventReceiver.receiveVnfStateChangedAlarm(org.openbaton.catalogue.mano.common.faultmanagement.VNFAlarmStateChangedNotification)
2017-10-16 19:24:35.797 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alarm/vr],methods=[POST],consumes=[application/json],produces=[application/json]}" onto public org.openbaton.catalogue.mano.common.monitoring.Alarm org.openbaton.faultmanagement.receivers.RestEventReceiver.receiveVRNewAlarm(org.openbaton.catalogue.mano.common.faultmanagement.VirtualizedResourceAlarmNotification)
2017-10-16 19:24:35.797 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/alarm/vr],methods=[PUT],consumes=[application/json],produces=[application/json]}" onto public org.openbaton.catalogue.mano.common.monitoring.Alarm org.openbaton.faultmanagement.receivers.RestEventReceiver.receiveVRStateChangedAlarm(org.openbaton.catalogue.mano.common.faultmanagement.VirtualizedResourceAlarmStateChangedNotification)
2017-10-16 19:24:35.799 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-10-16 19:24:35.800 INFO 7367 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-10-16 19:24:35.827 INFO 7367 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-16 19:24:35.827 INFO 7367 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-16 19:24:35.861 INFO 7367 --- [main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-10-16 19:24:36.104 INFO 7367 --- [main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-10-16 19:24:36.110 INFO 7367 --- [main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'getConnectionFactory' has been autodetected for JMX exposure
2017-10-16 19:24:36.113 INFO 7367 --- [main] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'getConnectionFactory': registering with JMX server as MBean [org.springframework.amqp.rabbit.connection:name=getConnectionFactory,type=CachingConnectionFactory]
2017-10-16 19:24:36.128 INFO 7367 --- [main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147482648
2017-10-16 19:24:36.128 INFO 7367 --- [main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2017-10-16 19:24:36.184 INFO 7367 --- [setCreationMessageContainer-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: getConnectionFactory#731afd18:0/SimpleConnection@79e29668 [delegate=amqp://admin@172.31.0.136:5672/, localPort= 34708]
2017-10-16 19:24:36.189 INFO 7367 --- [setCreationMessageContainer-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (nfvo.fm.nsr.create) durable:false, auto-delete:true, exclusive:false. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2017-10-16 19:24:36.189 INFO 7367 --- [setCreationMessageContainer-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (nfvo.fm.vnf.events) durable:false, auto-delete:true, exclusive:false. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2017-10-16 19:24:36.189 INFO 7367 --- [setCreationMessageContainer-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (nfvo.fm.nsr.delete) durable:false, auto-delete:true, exclusive:false. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
2017-10-16 19:24:36.275 INFO 7367 --- [main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9000 (http)
2017-10-16 19:24:36.277 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : Nfvo IP: 172.31.0.136: Nfvo Port: 8443
2017-10-16 19:24:36.278 INFO 7367 --- [main] o.openbaton.faultmanagement.utils.Utils : Waiting until NFVO is available...
2017-10-16 19:24:36.278 INFO 7367 --- [main] o.openbaton.faultmanagement.utils.Utils : NFVO is listening on port 8443 at 172.31.0.136
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : instantiating monitoringPluginCaller:
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : rabbitmqIp: 172.31.0.136
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : rabbitmqUsr: admin
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : rabbitmqPwd: openbaton
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : rabbitmqPort: 5672
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : monitoringPluginType: zabbix-plugin
2017-10-16 19:24:36.278 INFO 7367 --- [main] org.openbaton.faultmanagement.Starter : monitoringPluginName: zabbix
2017-10-16 19:24:36.512 DEBUG 7367 --- [main] org.openbaton.faultmanagement.Starter : MonitoringPluginCaller obtained
2017-10-16 19:24:36.513 DEBUG 7367 --- [main] o.o.f.r.NFVORequestorWrapperImpl : Trying to connect to the NFVO...
2017-10-16 19:24:36.523 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Registering Service fm-system
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : File Length based on Array: 17
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 0 : 78
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 1 : 105
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 2 : 117
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 3 : 86
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 4 : 116
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 5 : 68
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 6 : 101
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 7 : 106
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 8 : 65
2017-10-16 19:24:36.528 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 9 : 111
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 10 : 76
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 11 : 93
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 12 : 120
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 13 : 119
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 14 : 92
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 15 : 83
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 1: Byte 16 : 10
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : 2nd Array Length: 16
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 0 : 78
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 1 : 105
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 2 : 117
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 3 : 86
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 4 : 116
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 5 : 68
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 6 : 101
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 7 : 106
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 8 : 65
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 9 : 111
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 10 : 76
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 11 : 93
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 12 : 120
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 13 : 119
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 14 : 92
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Array 2: Byte 15 : 83
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : File Content: NiuVtDejAoL]xw\S
2017-10-16 19:24:36.529 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Content Length: 16
2017-10-16 19:24:36.548 DEBUG 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Post: https://172.31.0.136:8443/api/v1/components/services/register
2017-10-16 19:24:36.652 ERROR 7367 --- [main] org.openbaton.sdk.api.util.RestUtils : Status expected: 201 obtained: 406
2017-10-16 19:24:36.653 ERROR 7367 --- [main] org.openbaton.sdk.api.util.RestUtils : httpresponse: HttpResponseProxy{HTTP/1.1 406 [X-Content-Type-Options: nosniff, X-XSS-Protection: 1; mode=block, Cache-Control: no-cache, no-store, max-age=0, must-revalidate, Pragma: no-cache, Expires: 0, Strict-Transport-Security: max-age=31536000 ; includeSubDomains, X-Frame-Options: DENY, X-Application-Context: NFVO OpenBaton:8443, Content-Length: 0, Date: Mon, 16 Oct 2017 23:24:36 GMT] [Content-Length: 0,Chunked: false]}
2017-10-16 19:24:36.654 ERROR 7367 --- [main] org.openbaton.sdk.api.util.RestUtils : Body:
2017-10-16 19:24:36.665 ERROR 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
org.openbaton.sdk.api.exception.SDKException: org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
at org.openbaton.sdk.api.util.RestRequest.getAccessToken(RestRequest.java:1036) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.checkToken(RestRequest.java:645) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGetAll(RestRequest.java:739) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGet(RestRequest.java:725) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.AbstractRestAgent.findAll(AbstractRestAgent.java:131) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.setProjectId(NFVORequestorWrapperImpl.java:92) [classes!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.subscribe(NFVORequestorWrapperImpl.java:183) [classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.sendSubscription(EventSubscriptionManagerImpl.java:82) [classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.subscribeToNFVO(EventSubscriptionManagerImpl.java:117) [classes!/:na]
at org.openbaton.faultmanagement.Starter.run(Starter.java:123) [classes!/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.openbaton.faultmanagement.Application.main(Application.java:33) [classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [fm-system-1.2.6-SNAPSHOT.jar:na]
Caused by: org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
at org.openbaton.sdk.api.util.RestUtils.checkStatus(RestUtils.java:41) ~[sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.getAccessToken(RestRequest.java:1023) [sdk-4.0.1-SNAPSHOT.jar!/:na]
... 24 common frames omitted
2017-10-16 19:24:36.667 ERROR 7367 --- [main] org.openbaton.sdk.api.rest.ProjectAgent : Could not get service token. The reason is: org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
org.openbaton.sdk.api.exception.SDKException: Could not get service token. The reason is: org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
at org.openbaton.sdk.api.util.RestRequest.checkToken(RestRequest.java:652) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGetAll(RestRequest.java:739) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGet(RestRequest.java:725) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.AbstractRestAgent.findAll(AbstractRestAgent.java:131) [sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.setProjectId(NFVORequestorWrapperImpl.java:92) [classes!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.subscribe(NFVORequestorWrapperImpl.java:183) [classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.sendSubscription(EventSubscriptionManagerImpl.java:82) [classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.subscribeToNFVO(EventSubscriptionManagerImpl.java:117) [classes!/:na]
at org.openbaton.faultmanagement.Starter.run(Starter.java:123) [classes!/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.openbaton.faultmanagement.Application.main(Application.java:33) [classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [fm-system-1.2.6-SNAPSHOT.jar:na]
2017-10-16 19:24:36.672 INFO 7367 --- [main] utoConfigurationReportLoggingInitializer :
Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-10-16 19:24:36.676 ERROR 7367 --- [main] o.s.boot.SpringApplication : Application startup failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:735) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:716) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:703) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:304) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1118) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1107) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
at org.openbaton.faultmanagement.Application.main(Application.java:33) [classes!/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [fm-system-1.2.6-SNAPSHOT.jar:na]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [fm-system-1.2.6-SNAPSHOT.jar:na]
Caused by: org.openbaton.sdk.api.exception.SDKException: Could not get service token. The reason is: org.openbaton.sdk.api.exception.SDKException: Status is 406. The reason is:
at org.openbaton.sdk.api.util.RestRequest.checkToken(RestRequest.java:652) ~[sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGetAll(RestRequest.java:739) ~[sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.RestRequest.requestGet(RestRequest.java:725) ~[sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.sdk.api.util.AbstractRestAgent.findAll(AbstractRestAgent.java:131) ~[sdk-4.0.1-SNAPSHOT.jar!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.setProjectId(NFVORequestorWrapperImpl.java:92) ~[classes!/:na]
at org.openbaton.faultmanagement.requestor.NFVORequestorWrapperImpl.subscribe(NFVORequestorWrapperImpl.java:183) ~[classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.sendSubscription(EventSubscriptionManagerImpl.java:82) ~[classes!/:na]
at org.openbaton.faultmanagement.subscriber.EventSubscriptionManagerImpl.subscribeToNFVO(EventSubscriptionManagerImpl.java:117) ~[classes!/:na]
at org.openbaton.faultmanagement.Starter.run(Starter.java:123) ~[classes!/:na]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:732) [spring-boot-1.5.6.RELEASE.jar!/:1.5.6.RELEASE]
... 14 common frames omitted
2017-10-16 19:24:36.679 INFO 7367 --- [main] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@28c97a5: startup date [Mon Oct 16 19:24:29 EDT 2017]; root of context hierarchy
2017-10-16 19:24:36.696 DEBUG 7367 --- [main] o.o.f.s.EventSubscriptionManagerImpl : unsubscribing vnf event subscriptions
2017-10-16 19:24:36.737 INFO 7367 --- [main] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2017-10-16 19:24:36.872 INFO 7367 --- [main] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2017-10-16 19:24:36.876 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2017-10-16 19:24:37.241 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2017-10-16 19:24:37.247 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2017-10-16 19:24:38.242 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2017-10-16 19:24:38.244 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2017-10-16 19:24:38.247 INFO 7367 --- [main] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2017-10-16 19:24:38.248 INFO 7367 --- [main] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase -2147482648
2017-10-16 19:24:38.248 INFO 7367 --- [main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2017-10-16 19:24:38.248 INFO 7367 --- [main] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans
2017-10-16 19:24:38.259 INFO 7367 --- [main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
/*
* Copyright (c) 2016 Open Baton (http://www.openbaton.org)
*
* 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.
*
*/
package org.openbaton.sdk.api.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mashape.unirest.http.JsonNode;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.SSLContext;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.openbaton.catalogue.nfvo.VNFPackage;
import org.openbaton.nfvo.common.utils.key.KeyHelper;
import org.openbaton.sdk.api.exception.SDKException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** OpenBaton api request abstraction for all requester. Shares common data and methods. */
public abstract class RestRequest {
private static final String KEY_FILE_PATH = "/etc/openbaton/service-key";
private static final String SDK_PROPERTIES_FILE = "sdk.api.properties";
private String keyFilePath;
private Logger log = LoggerFactory.getLogger(this.getClass());
protected final String baseUrl;
protected final String pathUrl;
// protected final String url;
protected Gson mapper;
private String username;
private String password;
private boolean isService;
private String serviceName;
private String serviceTokenUrl;
private static final PropertyReader propertyReader = new PropertyReader(SDK_PROPERTIES_FILE);
public String getProjectId() {
return projectId;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
private String projectId;
private String authStr = "openbatonOSClient" + ":" + "secret";
private String encoding = Base64.encodeBase64String(authStr.getBytes());
private final String provider;
private String token = null;
private String bearerToken = null;
private CloseableHttpClient httpClient;
private RequestConfig config =
RequestConfig.custom().setConnectionRequestTimeout(10000).setConnectTimeout(60000).build();
/**
* RestRequest constructor for normal users.
*
* @param username
* @param password
* @param projectId
* @param sslEnabled
* @param nfvoIp
* @param nfvoPort
* @param path
* @param version
*/
public RestRequest(
String username,
String password,
String projectId,
boolean sslEnabled,
final String nfvoIp,
String nfvoPort,
String path,
String version) {
if (sslEnabled) {
this.baseUrl = "https://" + nfvoIp + ":" + nfvoPort + "/api/v" + version;
this.provider = "https://" + nfvoIp + ":" + nfvoPort + "/oauth/token";
this.httpClient = getHttpClientForSsl();
} else {
this.baseUrl = "http://" + nfvoIp + ":" + nfvoPort + "/api/v" + version;
this.provider = "http://" + nfvoIp + ":" + nfvoPort + "/oauth/token";
this.httpClient =
HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setConnectionManager(new PoolingHttpClientConnectionManager())
.build();
}
this.pathUrl = this.baseUrl + path;
this.serviceTokenUrl = this.baseUrl + propertyReader.getRestUrl("Service") + "/register";
this.username = username;
this.password = password;
this.isService = false;
this.projectId = projectId;
GsonBuilder builder = new GsonBuilder();
//builder.registerTypeAdapter(Date.class, new GsonSerializerDate());
//builder.registerTypeAdapter(Date.class, new GsonDeserializerDate());
this.mapper = builder.setPrettyPrinting().create();
}
/**
* RestRequest constructor for services.
*
* @param serviceName
* @param projectId
* @param sslEnabled
* @param nfvoIp
* @param nfvoPort
* @param path
* @param version
* @param keyFilePath
*/
public RestRequest(
String serviceName,
String projectId,
boolean sslEnabled,
final String nfvoIp,
String nfvoPort,
String path,
String version,
String keyFilePath)
throws FileNotFoundException {
if (sslEnabled) {
this.baseUrl = "https://" + nfvoIp + ":" + nfvoPort + "/api/v" + version;
this.provider = "https://" + nfvoIp + ":" + nfvoPort + "/oauth/token";
this.httpClient = getHttpClientForSsl();
} else {
this.baseUrl = "http://" + nfvoIp + ":" + nfvoPort + "/api/v" + version;
this.provider = "http://" + nfvoIp + ":" + nfvoPort + "/oauth/token";
this.httpClient =
HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setConnectionManager(new PoolingHttpClientConnectionManager())
.build();
}
this.pathUrl = this.baseUrl + path;
this.serviceTokenUrl = this.baseUrl + propertyReader.getRestUrl("Service") + "/register";
this.serviceName = serviceName;
this.isService = true;
this.projectId = projectId;
GsonBuilder builder = new GsonBuilder();
//builder.registerTypeAdapter(Date.class, new GsonSerializerDate());
//builder.registerTypeAdapter(Date.class, new GsonDeserializerDate());
this.mapper = builder.setPrettyPrinting().create();
if (keyFilePath != null) this.keyFilePath = keyFilePath;
else this.keyFilePath = propertyReader.getSimpleProperty("key-file-location", KEY_FILE_PATH);
if (!new File(this.keyFilePath).exists()) {
log.error("missing key file for services");
throw new FileNotFoundException("missing key file for services");
}
}
/**
* Does the POST Request
*
* @param id
* @return String
* @throws SDKException
*/
public String requestPost(final String id) throws SDKException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.debug("Executing post on: " + this.pathUrl + "/" + id);
httpPost = new HttpPost(this.pathUrl + "/" + id);
preparePostHeader(httpPost, "application/json", "application/json");
response = httpClient.execute(httpPost);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_CREATED);
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
response.close();
log.trace("received: " + result);
httpPost.releaseConnection();
return result;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpPost != null) {
httpPost.releaseConnection();
}
throw new SDKException(
"Could not http-post or open the object properly",
e.getStackTrace(),
"Could not http-post or open the object properly because: " + e.getMessage());
} catch (SDKException e) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpPost != null) {
httpPost.releaseConnection();
}
return requestPost(id);
} else {
if (httpPost != null) {
httpPost.releaseConnection();
}
try {
throw new SDKException(
"Status is " + response.getStatusLine().getStatusCode(),
new StackTraceElement[0],
EntityUtils.toString(response.getEntity()));
} catch (IOException e1) {
e1.printStackTrace();
throw new SDKException(
"Status is " + response.getStatusLine().getStatusCode(),
new StackTraceElement[0],
"could not provide reason because: " + e.getMessage());
}
}
}
}
/**
* Executes a http post with to a given url, while serializing the object content as json and
* returning the response
*
* @param object the object content to be serialized as json
* @return a string containing the response content
*/
public Serializable requestPost(final Serializable object) throws SDKException {
return requestPost("", object);
}
public Serializable requestPost(
final String id, final Serializable object, final String acceptMime, final String contentMime)
throws SDKException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
log.trace("Object is: " + object);
String fileJSONNode;
if (object instanceof String) {
fileJSONNode = (String) object;
} else {
fileJSONNode = mapper.toJson(object);
}
log.trace("sending: " + fileJSONNode.toString());
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.debug("Executing post on: " + this.pathUrl + "/" + id);
httpPost = new HttpPost(this.pathUrl + "/" + id);
preparePostHeader(httpPost, acceptMime, contentMime);
httpPost.setEntity(new StringEntity(fileJSONNode));
response = httpClient.execute(httpPost);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_CREATED);
// return the response of the request
Serializable result = null;
if (response.getEntity() != null) {
result = EntityUtils.toByteArray(response.getEntity());
}
return result;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpPost != null) {
httpPost.releaseConnection();
}
throw new SDKException(
"Could not http-post or open the object properly",
e.getStackTrace(),
"Could not http-post or open the object properly because: " + e.getMessage());
} catch (SDKException e) {
if (response != null
&& response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpPost != null) {
httpPost.releaseConnection();
}
return requestPost(id);
} else if (response != null) {
throw e;
} else {
throw e;
}
}
}
/**
* Add accept, content-type, projectId and token headers to an HttpPost object.
*
* @param httpPost
* @param acceptMimeType
* @param contentMimeType
*/
private void preparePostHeader(HttpPost httpPost, String acceptMimeType, String contentMimeType) {
if (acceptMimeType != null && !acceptMimeType.equals("")) {
httpPost.setHeader(new BasicHeader("accept", acceptMimeType));
}
if (contentMimeType != null && !contentMimeType.equals("")) {
httpPost.setHeader(new BasicHeader("Content-Type", contentMimeType));
}
httpPost.setHeader(new BasicHeader("project-id", projectId));
if (token != null && bearerToken != null) {
httpPost.setHeader(new BasicHeader("authorization", bearerToken.replaceAll("\"", "")));
}
}
private CloseableHttpResponse genericPost(
String id, Serializable object, String acceptMimeType, String contentMimeType)
throws SDKException, IOException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
log.trace("Object is: " + object);
String fileJSONNode;
if (object instanceof String) {
fileJSONNode = (String) object;
} else {
fileJSONNode = mapper.toJson(object);
}
log.trace("sending: " + fileJSONNode.toString());
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.debug("Executing post on: " + this.pathUrl + "/" + id);
httpPost = new HttpPost(this.pathUrl + "/" + id);
preparePostHeader(httpPost, acceptMimeType, contentMimeType);
httpPost.setEntity(new StringEntity(fileJSONNode));
response = httpClient.execute(httpPost);
return response;
}
public Serializable requestPost(final String id, final Serializable object) throws SDKException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
log.trace("Object is: " + object);
String fileJSONNode;
if (object instanceof String) {
fileJSONNode = (String) object;
} else {
fileJSONNode = mapper.toJson(object);
}
log.trace("sending: " + fileJSONNode.toString());
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.debug("Executing post on: " + this.pathUrl + "/" + id);
httpPost = new HttpPost(this.pathUrl + "/" + id);
if (!(object instanceof String)) {
preparePostHeader(httpPost, "application/json", "application/json");
} else {
preparePostHeader(httpPost, null, null);
}
httpPost.setEntity(new StringEntity(fileJSONNode));
response = httpClient.execute(httpPost);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_CREATED);
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
if (object instanceof String) {
return result;
}
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(result);
result = mapper.toJson(jsonElement);
log.trace("received: " + result);
log.trace("Casting it into: " + object.getClass());
return mapper.fromJson(result, object.getClass());
}
response.close();
httpPost.releaseConnection();
return null;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpPost != null) {
httpPost.releaseConnection();
}
throw new SDKException(
"Could not http-post or open the object properly",
e.getStackTrace(),
"Could not http-post or open the object properly because: " + e.getMessage());
} catch (SDKException e) {
if (response != null
&& response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpPost != null) {
httpPost.releaseConnection();
}
return requestPost(id);
} else if (response != null) {
throw e;
} else {
throw e;
}
}
}
/**
* Executes a http post with to a given url, while serializing the object content as json. The
* type parameter specifies to which object type the post response should be mapped before
* returning it. This can be useful if the method's return type is not the same as the type of the
* object parameter.
*
* @param object the object content to be serialized as json
* @param type the object type to which the response should be mapped
* @return a string containing the response content
*/
public Serializable requestPost(final String id, final Serializable object, final Type type)
throws SDKException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
log.trace("Object is: " + object);
String fileJSONNode = mapper.toJson(object);
log.trace("sending: " + fileJSONNode.toString());
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.debug("Executing post on: " + this.pathUrl + "/" + id);
httpPost = new HttpPost(this.pathUrl + "/" + id);
preparePostHeader(httpPost, "application/json", "application/json");
httpPost.setEntity(new StringEntity(fileJSONNode));
response = httpClient.execute(httpPost);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_CREATED);
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(result);
result = mapper.toJson(jsonElement);
log.trace("received: " + result);
log.trace("Casting it into: " + type);
return mapper.fromJson(result, type);
}
response.close();
httpPost.releaseConnection();
return null;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpPost != null) {
httpPost.releaseConnection();
}
throw new SDKException(
"Could not http-post or open the object properly",
e.getStackTrace(),
"Could not http-post or open the object properly because: " + e.getMessage());
} catch (SDKException e) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpPost != null) {
httpPost.releaseConnection();
}
return requestPost(id);
} else {
if (httpPost != null) {
httpPost.releaseConnection();
}
try {
throw new SDKException(
"Status is " + response.getStatusLine().getStatusCode(),
new StackTraceElement[0],
EntityUtils.toString(response.getEntity()));
} catch (IOException e1) {
e1.printStackTrace();
throw new SDKException(
"Status is " + response.getStatusLine().getStatusCode(),
new StackTraceElement[0],
"could not provide reason because: " + e.getMessage());
}
}
}
}
/**
* Used to upload tar files to the NFVO for creating VNFPackages.
*
* @param f the tar file containing the VNFPackage
* @return the created VNFPackage object
* @throws SDKException
*/
public VNFPackage requestPostPackage(final File f) throws SDKException {
CloseableHttpResponse response = null;
HttpPost httpPost = null;
try {
checkToken();
log.debug("Executing post on " + pathUrl);
httpPost = new HttpPost(this.pathUrl);
preparePostHeader(httpPost, "multipart/form-data", null);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
multipartEntityBuilder.addBinaryBody("file", f);
httpPost.setEntity(multipartEntityBuilder.build());
response = httpClient.execute(httpPost);
} catch (ClientProtocolException e) {
httpPost.releaseConnection();
throw new SDKException(
"Could not create VNFPackage from file " + f.getName(),
e.getStackTrace(),
e.getMessage());
} catch (IOException e) {
httpPost.releaseConnection();
throw new SDKException(
"Could not create VNFPackage from file " + f.getName(),
e.getStackTrace(),
e.getMessage());
}
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_OK);
// return the response of the request
String result = "";
if (response.getEntity() != null) {
try {
result = EntityUtils.toString(response.getEntity());
} catch (IOException e) {
e.printStackTrace();
}
}
if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(result);
result = mapper.toJson(jsonElement);
log.debug("Uploaded the VNFPackage");
log.trace("received: " + result);
log.trace("Casting it into: " + VNFPackage.class);
httpPost.releaseConnection();
return mapper.fromJson(result, VNFPackage.class);
}
httpPost.releaseConnection();
return null;
}
private void checkToken() throws SDKException {
try {
if (this.token == null
&& ((isService && this.serviceName != null && !this.serviceName.equals(""))
|| (!((this.username == null && this.username.equals(""))
|| (this.password == null || this.password.equals("")))))) {
getAccessToken();
}
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new SDKException(
(isService ? "Could not get service token" : "Could not get user token"),
e.getStackTrace(),
e.getMessage());
}
}
private JsonNode getJsonNode(Serializable object) throws IOException {
return new JsonNode(mapper.toJson(object));
}
/**
* Executes a http delete with to a given id
*
* @param id the id path used for the api request
*/
public void requestDelete(final String id) throws SDKException {
CloseableHttpResponse response = null;
HttpDelete httpDelete = null;
try {
log.debug("pathUrl: " + pathUrl);
log.debug("id: " + pathUrl + "/" + id);
checkToken();
// call the api here
log.info("Executing delete on: " + this.pathUrl + "/" + id);
httpDelete = new HttpDelete(this.pathUrl + "/" + id);
httpDelete.setHeader(new BasicHeader("project-id", projectId));
if (token != null) {
httpDelete.setHeader(new BasicHeader("authorization", bearerToken.replaceAll("\"", "")));
}
response = httpClient.execute(httpDelete);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_NO_CONTENT);
httpDelete.releaseConnection();
// return the response of the request
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpDelete != null) {
httpDelete.releaseConnection();
}
throw new SDKException("Could not http-delete", e.getStackTrace(), e.getMessage());
} catch (SDKException e) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpDelete != null) {
httpDelete.releaseConnection();
}
requestDelete(id);
return;
}
if (httpDelete != null) {
httpDelete.releaseConnection();
}
throw new SDKException(
"Could not http-delete or the api response was wrong", e.getStackTrace(), e.getMessage());
}
}
/**
* Executes a http get with to a given id
*
* @param id the id path used for the api request
* @return a string containing he response content
*/
public Object requestGet(final String id, Class type) throws SDKException {
String url = this.pathUrl;
if (id != null) {
url += "/" + id;
return requestGetWithStatus(url, null, type);
} else {
return requestGetAll(url, type, null);
}
}
protected Object requestGetAll(String url, Class type) throws SDKException {
url = this.pathUrl + "/" + url;
return requestGetAll(url, type, null);
}
private Object requestGetAll(String url, Class type, final Integer httpStatus)
throws SDKException {
CloseableHttpResponse response = null;
HttpGet httpGet = null;
try {
checkToken();
// call the api here
log.debug("Executing get on: " + url);
httpGet = new HttpGet(url);
httpGet.setHeader(new BasicHeader("project-id", projectId));
if (token != null) {
httpGet.setHeader(new BasicHeader("authorization", bearerToken.replaceAll("\"", "")));
}
response = httpClient.execute(httpGet);
// check response status
if (httpStatus != null) {
RestUtils.checkStatus(response, httpStatus);
} else {
RestUtils.checkStatus(response, HttpURLConnection.HTTP_OK);
}
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
response.close();
httpGet.releaseConnection();
log.trace("result is: " + result);
Class<?> aClass = Array.newInstance(type, 3).getClass();
log.trace("class is: " + aClass);
Object[] o = (Object[]) this.mapper.fromJson(result, aClass);
log.trace("deserialized is: " + o);
return o;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw new SDKException("Could not http-get", e.getStackTrace(), e.getMessage());
} catch (SDKException e) {
if (response != null) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpGet != null) {
httpGet.releaseConnection();
}
return requestGetAll(url, type, httpStatus);
} else {
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw new SDKException("Could not authorize", e.getStackTrace(), e.getMessage());
}
} else {
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw e;
}
}
}
/**
* Executes a http get with to a given id, and possible executed an http (accept) status check of
* the response if an httpStatus is delivered. If httpStatus is null, no check will be executed.
*
* @param url the id path used for the api request
* @param httpStatus the http status to be checked.
* @param type
* @return a string containing the response content
*/
private Object requestGetWithStatus(final String url, final Integer httpStatus, Class type)
throws SDKException {
CloseableHttpResponse response = null;
HttpGet httpGet = null;
try {
checkToken();
// call the api here
log.debug("Executing get on: " + url);
httpGet = new HttpGet(url);
httpGet.setHeader(new BasicHeader("project-id", projectId));
if (token != null) {
httpGet.setHeader(new BasicHeader("authorization", bearerToken.replaceAll("\"", "")));
}
response = httpClient.execute(httpGet);
// check response status
if (httpStatus != null) {
RestUtils.checkStatus(response, httpStatus);
} else {
RestUtils.checkStatus(response, HttpURLConnection.HTTP_OK);
}
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
response.close();
httpGet.releaseConnection();
log.trace("result is: " + result);
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(result);
result = mapper.toJson(jsonElement);
log.trace("result is: " + result);
Class<?> aClass = Array.newInstance(type, 1).getClass();
log.trace("class is: " + aClass);
return mapper.fromJson(result, type);
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw new SDKException("Could not http-get", e.getStackTrace(), e.getMessage());
} catch (SDKException e) {
if (response != null) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpGet != null) {
httpGet.releaseConnection();
}
return requestGetWithStatus(url, httpStatus, type);
} else {
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw new SDKException("Could not authorize", e.getStackTrace(), e.getMessage());
}
} else {
log.error(e.getMessage(), e);
if (httpGet != null) {
httpGet.releaseConnection();
}
throw e;
}
} finally {
if (httpGet != null) {
httpGet.releaseConnection();
}
}
}
/**
* Executes a http get with to a given url, in contrast to the normal get it uses an http (accept)
* status check of the response
*
* @param url the url path used for the api request
* @return a string containing the response content
*/
public Object requestGetWithStatusAccepted(String url, Class type) throws SDKException {
url = this.pathUrl + "/" + url;
return requestGetWithStatus(url, new Integer(HttpURLConnection.HTTP_ACCEPTED), type);
}
/**
* Executes a http put with to a given id, while serializing the object content as json and
* returning the response
*
* @param id the id path used for the api request
* @param object the object content to be serialized as json
* @return a string containing the response content
*/
public Serializable requestPut(final String id, final Serializable object) throws SDKException {
CloseableHttpResponse response = null;
HttpPut httpPut = null;
try {
log.trace("Object is: " + object);
String fileJSONNode = mapper.toJson(object);
checkToken();
// call the api here
log.debug("Executing put on: " + this.pathUrl + "/" + id);
httpPut = new HttpPut(this.pathUrl + "/" + id);
httpPut.setHeader(new BasicHeader("accept", "application/json"));
httpPut.setHeader(new BasicHeader("Content-Type", "application/json"));
httpPut.setHeader(new BasicHeader("project-id", projectId));
if (token != null) {
httpPut.setHeader(new BasicHeader("authorization", bearerToken.replaceAll("\"", "")));
}
httpPut.setEntity(new StringEntity(fileJSONNode));
response = httpClient.execute(httpPut);
// check response status
RestUtils.checkStatus(response, HttpURLConnection.HTTP_ACCEPTED);
// return the response of the request
String result = "";
if (response.getEntity() != null) {
result = EntityUtils.toString(response.getEntity());
}
if (response.getStatusLine().getStatusCode() != HttpURLConnection.HTTP_NO_CONTENT) {
response.close();
httpPut.releaseConnection();
JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(result);
result = mapper.toJson(jsonElement);
log.trace("received: " + result);
log.trace("Casting it into: " + object.getClass());
return mapper.fromJson(result, object.getClass());
}
response.close();
httpPut.releaseConnection();
return null;
} catch (IOException e) {
// catch request exceptions here
log.error(e.getMessage(), e);
if (httpPut != null) {
httpPut.releaseConnection();
}
throw new SDKException(
"Could not http-put or the api response was wrong or open the object properly",
e.getStackTrace(),
e.getMessage());
} catch (SDKException e) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
token = null;
if (httpPut != null) {
httpPut.releaseConnection();
}
return requestPut(id, object);
} else {
if (httpPut != null) {
httpPut.releaseConnection();
}
throw new SDKException(
"Could not http-put or the api response was wrong or open the object properly",
e.getStackTrace(),
e.getMessage());
}
} finally {
if (httpPut != null) {
httpPut.releaseConnection();
}
}
}
private void getAccessToken() throws IOException, SDKException {
if (isService) {
try {
log.debug("Registering Service " + serviceName);
String key_data_prv =
new String(Files.readAllBytes(Paths.get(this.keyFilePath)), StandardCharsets.UTF_8);
File file = new File(this.keyFilePath);
FileInputStream fin = null;
fin = new FileInputStream(file);
byte fileContent[] = new byte[(int) file.length()];
log.debug("File Length based on Array: " + fileContent.length);
fin.read(fileContent);
for (int i = 0; i < fileContent.length; i++)
log.debug("Array 1: Byte " + i + " : " + fileContent[i]);
byte fileContent2[] = Arrays.copyOf(fileContent, 16);
log.debug("2nd Array Length: " + fileContent2.length);
for (int i = 0; i < fileContent2.length; i++)
log.debug("Array 2: Byte " + i + " : " + fileContent2[i]);
String key_data = new String(fileContent2);
log.debug("File Content: " + key_data);
log.debug("Content Length: " + key_data.length());
String encryptedMessage =
KeyHelper.encryptNew(
"{\"name\":\"" + serviceName + "\",\"action\":\"register\"}", key_data);
CloseableHttpResponse response = null;
HttpPost httpPost = new HttpPost(this.serviceTokenUrl);
httpPost.setHeader(new BasicHeader("accept", "text/plain,application/json"));
httpPost.setHeader(new BasicHeader("Content-Type", "text/plain"));
httpPost.setEntity(new StringEntity(encryptedMessage));
log.debug("Post: " + httpPost.getURI());
response = httpClient.execute(httpPost);
RestUtils.checkStatus(response, HttpURLConnection.HTTP_CREATED);
String encryptedToken = "";
if (response.getEntity() != null) {
encryptedToken = EntityUtils.toString(response.getEntity());
}
response.close();
httpPost.releaseConnection();
String decryptedToken = KeyHelper.decryptNew(encryptedToken, key_data);
log.trace("Token is: " + decryptedToken);
this.token = decryptedToken;
this.bearerToken = "Bearer " + this.token;
} catch (Exception e) {
throw new SDKException(e);
}
} else {
HttpPost httpPost = new HttpPost(provider);
httpPost.setHeader("Authorization", "Basic " + encoding);
List<BasicNameValuePair> parametersBody = new ArrayList<>();
parametersBody.add(new BasicNameValuePair("grant_type", "password"));
parametersBody.add(new BasicNameValuePair("username", this.username));
parametersBody.add(new BasicNameValuePair("password", this.password));
log.debug("Username is: " + username);
log.debug("Password is: " + password);
httpPost.setEntity(new UrlEncodedFormEntity(parametersBody, StandardCharsets.UTF_8));
CloseableHttpResponse response = null;
log.debug("httpPost is: " + httpPost.toString());
response = httpClient.execute(httpPost);
String responseString = null;
responseString = EntityUtils.toString(response.getEntity());
int statusCode = response.getStatusLine().getStatusCode();
response.close();
httpPost.releaseConnection();
log.trace(statusCode + ": " + responseString);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
if (statusCode != 200) {
JsonObject error = gson.fromJson(responseString, JsonObject.class);
JsonElement detailMessage = error.get("detailMessage");
if (detailMessage == null) {
detailMessage = error.get("errorMessage");
}
if (detailMessage == null) {
detailMessage = error.get("message");
}
if (detailMessage == null) {
detailMessage = error.get("description");
}
if (detailMessage == null) {
detailMessage = error.get("errorDescription");
}
log.error(
"Status Code ["
+ statusCode
+ "]: Error signing-in ["
+ (detailMessage != null ? detailMessage.getAsString() : "no error description")
+ "]");
if (detailMessage == null) {
log.error("Got Error from server: \n" + gson.toJson(error));
}
throw new SDKException(
"Status Code ["
+ statusCode
+ "]: Error signing-in ["
+ (detailMessage != null ? detailMessage.getAsString() : "no error description")
+ "]",
new StackTraceElement[0],
(detailMessage != null ? detailMessage.getAsString() : "no error description"));
}
JsonObject jobj = new Gson().fromJson(responseString, JsonObject.class);
log.trace("JsonTokenAccess is: " + jobj.toString());
try {
String token = jobj.get("value").getAsString();
log.trace(token);
bearerToken = "Bearer " + token;
this.token = token;
} catch (NullPointerException e) {
String error = jobj.get("error").getAsString();
if (error.equals("invalid_grant")) {
throw new SDKException(
"Error during authentication: " + jobj.get("error_description").getAsString(),
e.getStackTrace(),
e.getMessage());
}
}
}
}
private CloseableHttpClient getHttpClientForSsl() {
SSLContext sslContext = null;
try {
sslContext =
SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
} catch (NoSuchAlgorithmException e) {
log.error("Could not initialize the HttpClient for SSL connections");
log.error(e.getMessage(), e);
} catch (KeyManagementException e) {
log.error("Could not initialize the HttpClient for SSL connections");
log.error(e.getMessage(), e);
} catch (KeyStoreException e) {
log.error("Could not initialize the HttpClient for SSL connections");
log.error(e.getMessage(), e);
}
// necessary to trust self signed certificates
SSLConnectionSocketFactory sslConnectionSocketFactory =
new SSLConnectionSocketFactory(
sslContext, new String[] {"TLSv1"}, null, new NoopHostnameVerifier());
Registry<ConnectionSocketFactory> socketFactoryRegistry =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", sslConnectionSocketFactory)
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryRegistry))
.setSSLSocketFactory(sslConnectionSocketFactory)
.build();
}
public static void main(String[] args) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment