| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.nifi.registry.web.api; |
| |
| import com.fasterxml.jackson.annotation.JsonInclude; |
| import com.fasterxml.jackson.databind.DeserializationFeature; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector; |
| import org.apache.nifi.registry.client.NiFiRegistryClientConfig; |
| import org.apache.nifi.registry.db.DatabaseProfileValueSource; |
| import org.apache.nifi.registry.properties.NiFiRegistryProperties; |
| import org.glassfish.jersey.client.ClientConfig; |
| import org.glassfish.jersey.jackson.internal.jackson.jaxrs.json.JacksonJaxbJsonProvider; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.beans.factory.annotation.Value; |
| import org.springframework.boot.test.context.TestConfiguration; |
| import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory; |
| import org.springframework.boot.web.server.LocalServerPort; |
| import org.springframework.context.annotation.Bean; |
| import org.springframework.test.annotation.ProfileValueSourceConfiguration; |
| |
| import javax.annotation.PostConstruct; |
| import javax.net.ssl.HostnameVerifier; |
| import javax.net.ssl.SSLContext; |
| import javax.ws.rs.client.Client; |
| import javax.ws.rs.client.ClientBuilder; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.concurrent.locks.Lock; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| /** |
| * A base class to simplify creating integration tests against an API application running with an embedded server and volatile DB. |
| */ |
| @ProfileValueSourceConfiguration(DatabaseProfileValueSource.class) |
| public abstract class IntegrationTestBase { |
| |
| private static final String CONTEXT_PATH = "/nifi-registry-api"; |
| |
| @TestConfiguration |
| public static class TestConfigurationClass { |
| |
| /* REQUIRED: Any subclass extending IntegrationTestBase must add a Spring profile that defines a |
| * property value for this key containing the path to the nifi-registy.properties file to use to |
| * create a NiFiRegistryProperties Bean in the ApplicationContext. */ |
| @Value("${nifi.registry.properties.file}") |
| private String propertiesFileLocation; |
| |
| private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); |
| private final Lock readLock = lock.readLock(); |
| private NiFiRegistryProperties testProperties; |
| |
| @Bean |
| public JettyServletWebServerFactory jettyEmbeddedServletContainerFactory() { |
| JettyServletWebServerFactory jettyContainerFactory = new JettyServletWebServerFactory(); |
| jettyContainerFactory.setContextPath(CONTEXT_PATH); |
| return jettyContainerFactory; |
| } |
| |
| @Bean |
| public NiFiRegistryProperties getNiFiRegistryProperties() { |
| readLock.lock(); |
| try { |
| if (testProperties == null) { |
| testProperties = loadNiFiRegistryProperties(propertiesFileLocation); |
| } |
| } finally { |
| readLock.unlock(); |
| } |
| return testProperties; |
| } |
| |
| } |
| |
| @Autowired |
| private NiFiRegistryProperties properties; |
| |
| /* OPTIONAL: Any subclass that extends this base class MAY provide or specify a @TestConfiguration that provides a |
| * NiFiRegistryClientConfig @Bean. The properties specified should correspond with the integration test cases in |
| * the concrete subclass. See SecureFileIT for an example. */ |
| @Autowired(required = false) |
| private NiFiRegistryClientConfig clientConfig; |
| |
| /* This will be injected with the random port assigned to the embedded Jetty container. */ |
| @LocalServerPort |
| private int port; |
| |
| /** |
| * Subclasses can access this auto-configured JAX-RS client to communicate to the NiFi Registry Server |
| */ |
| protected Client client; |
| |
| @PostConstruct |
| void initialize() { |
| if (this.clientConfig != null) { |
| this.client = createClientFromConfig(this.clientConfig); |
| } else { |
| this.client = ClientBuilder.newClient(); |
| } |
| |
| } |
| |
| /** |
| * Subclasses can utilize this method to build a URL that has the correct protocol, hostname, and port |
| * for a given path. |
| * |
| * @param relativeResourcePath the path component of the resource you wish to access, relative to the |
| * base API URL, where the base includes the servlet context path. |
| * |
| * @return a String containing the absolute URL of the resource. |
| */ |
| String createURL(String relativeResourcePath) { |
| if (relativeResourcePath == null) { |
| throw new IllegalArgumentException("Resource path cannot be null"); |
| } |
| |
| final StringBuilder baseUriBuilder = new StringBuilder(createBaseURL()).append(CONTEXT_PATH); |
| |
| if (!relativeResourcePath.startsWith("/")) { |
| baseUriBuilder.append('/'); |
| } |
| baseUriBuilder.append(relativeResourcePath); |
| |
| return baseUriBuilder.toString(); |
| } |
| |
| /** |
| * Sub-classes can utilize this method to obtain the base-url for a client. |
| * |
| * @return a string containing the base url which includes the scheme, host, and port |
| */ |
| String createBaseURL() { |
| final boolean isSecure = this.properties.getSslPort() != null; |
| final String protocolSchema = isSecure ? "https" : "http"; |
| |
| final StringBuilder baseUriBuilder = new StringBuilder() |
| .append(protocolSchema).append("://localhost:").append(port); |
| |
| return baseUriBuilder.toString(); |
| } |
| |
| NiFiRegistryClientConfig createClientConfig(String baseUrl) { |
| final NiFiRegistryClientConfig.Builder builder = new NiFiRegistryClientConfig.Builder(); |
| builder.baseUrl(baseUrl); |
| |
| if (this.clientConfig != null) { |
| if (this.clientConfig.getSslContext() != null) { |
| builder.sslContext(this.clientConfig.getSslContext()); |
| } |
| |
| if (this.clientConfig.getHostnameVerifier() != null) { |
| builder.hostnameVerifier(this.clientConfig.getHostnameVerifier()); |
| } |
| } |
| |
| return builder.build(); |
| } |
| |
| /** |
| * A helper method for loading NiFiRegistryProperties by reading *.properties files from disk. |
| * |
| * @param propertiesFilePath The location of the properties file |
| * @return A NiFIRegistryProperties instance based on the properties file contents |
| */ |
| static NiFiRegistryProperties loadNiFiRegistryProperties(String propertiesFilePath) { |
| NiFiRegistryProperties properties = new NiFiRegistryProperties(); |
| try (final FileReader reader = new FileReader(propertiesFilePath)) { |
| properties.load(reader); |
| } catch (final IOException ioe) { |
| throw new RuntimeException("Unable to load properties: " + ioe, ioe); |
| } |
| return properties; |
| } |
| |
| private static Client createClientFromConfig(NiFiRegistryClientConfig registryClientConfig) { |
| |
| final ClientConfig clientConfig = new ClientConfig(); |
| clientConfig.register(jacksonJaxbJsonProvider()); |
| |
| final ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig); |
| |
| final SSLContext sslContext = registryClientConfig.getSslContext(); |
| if (sslContext != null) { |
| clientBuilder.sslContext(sslContext); |
| } |
| |
| final HostnameVerifier hostnameVerifier = registryClientConfig.getHostnameVerifier(); |
| if (hostnameVerifier != null) { |
| clientBuilder.hostnameVerifier(hostnameVerifier); |
| } |
| |
| return clientBuilder.build(); |
| } |
| |
| private static JacksonJaxbJsonProvider jacksonJaxbJsonProvider() { |
| JacksonJaxbJsonProvider jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider(); |
| |
| ObjectMapper mapper = new ObjectMapper(); |
| mapper.setPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL)); |
| mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory())); |
| // Ignore unknown properties so that deployed client remain compatible with future versions of NiFi Registry that add new fields |
| mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
| |
| jacksonJaxbJsonProvider.setMapper(mapper); |
| return jacksonJaxbJsonProvider; |
| } |
| |
| } |