diff --git a/src/main/java/de/ozgcloud/formcycle/HttpPostRequestBuilder.java b/src/main/java/de/ozgcloud/formcycle/HttpPostRequestBuilder.java index 7981dec40baab6c14f089db201756af645b2d152..6ee7e2cba4285552d73ba440a06f471fab030e30 100644 --- a/src/main/java/de/ozgcloud/formcycle/HttpPostRequestBuilder.java +++ b/src/main/java/de/ozgcloud/formcycle/HttpPostRequestBuilder.java @@ -23,6 +23,7 @@ package de.ozgcloud.formcycle; import java.util.Collection; +import java.util.regex.Pattern; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; @@ -35,10 +36,12 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor class HttpPostRequestBuilder { + static final String FORMCYCLE_ENDPOINT = "formData"; static final String FORM_DATA_KEY = "formData"; static final ContentType PROTOBUF_CONTENT_TYPE = ContentType.create("application/protobuf"); static final String ATTACHMENT_KEY = "attachments"; static final String REPRESENTATION_KEY = "representations"; + static final Pattern URL_WITH_ENDPOINT_PATTERN = Pattern.compile("^((https?://)?[^/]+)(/" + FORMCYCLE_ENDPOINT + ")$"); private final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create(); private final OzgCloudConfig cloudConfig; @@ -56,14 +59,25 @@ class HttpPostRequestBuilder { public HttpPostRequestBuilder withRepresentations(Collection<FormcycleAttachment> representations) { for (FormcycleAttachment representation : representations) { - entityBuilder.addBinaryBody(REPRESENTATION_KEY, representation.getContent(), representation.getContentType(), representation.getFileName()); + entityBuilder.addBinaryBody(REPRESENTATION_KEY, representation.getContent(), representation.getContentType(), + representation.getFileName()); } return this; } - public HttpPost build(){ - var httpPost = new HttpPost(cloudConfig.getEingangsAdapterUrl()); + public HttpPost build() { + var httpPost = new HttpPost(buildEingagsAdapterUrl()); httpPost.setEntity(entityBuilder.build()); return httpPost; } + + String buildEingagsAdapterUrl() { + String eingangsAdapterUrl = cloudConfig.getEingangsAdapterUrl(); + if (URL_WITH_ENDPOINT_PATTERN.matcher(eingangsAdapterUrl).matches()) { + return eingangsAdapterUrl; + } + return eingangsAdapterUrl.endsWith("/") + ? eingangsAdapterUrl + FORMCYCLE_ENDPOINT + : eingangsAdapterUrl + "/" + FORMCYCLE_ENDPOINT; + } } diff --git a/src/main/java/de/ozgcloud/formcycle/OzgCloudConfig.java b/src/main/java/de/ozgcloud/formcycle/OzgCloudConfig.java index 384624690145c4e54737db1358eedb1f66f8f845..c263f0abc5f049466703da952a1b8fcf395faa79 100644 --- a/src/main/java/de/ozgcloud/formcycle/OzgCloudConfig.java +++ b/src/main/java/de/ozgcloud/formcycle/OzgCloudConfig.java @@ -22,12 +22,22 @@ */ package de.ozgcloud.formcycle; +import java.io.Serializable; + import lombok.Builder; import lombok.Getter; +import lombok.Setter; @Builder @Getter -public class OzgCloudConfig { +public class OzgCloudConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final String KEY_EINGANGSADAPTER_URL = "eingangsAdapterUrl"; private String eingangsAdapterUrl; -} + @Setter + private ProxyConfig proxyConfig; + +} \ No newline at end of file diff --git a/src/main/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClient.java b/src/main/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClient.java index aaba4faef0b37cc0c0f983cd55c760d5a9dc8bdd..6e0d7145f83c5edb76eb91c987c7054a7194fa1d 100644 --- a/src/main/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClient.java +++ b/src/main/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClient.java @@ -22,16 +22,29 @@ */ package de.ozgcloud.formcycle; +import static java.util.Objects.*; +import static org.apache.commons.lang3.StringUtils.*; + import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Optional; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.conn.routing.HttpRoutePlanner; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.apache.http.protocol.HttpContext; import de.itvsh.kop.eingangsadapter.formcycle.FormCycleConfirmationResponse; import de.itvsh.kop.eingangsadapter.formcycle.FormCycleFormData; @@ -44,18 +57,111 @@ public class OzgCloudFormDataHttpClient { static final int HTTPCLIENT_TIMEOUT = 10 * 60 * 1000; private final OzgCloudConfig config; + private final SystemPropertiesProvider systemPropertiesProvider; + private Optional<ProxyConfig> systemProxyConfig; + + private BasicCredentialsProvider credentialsProvider; + private HttpClientContext context; + private HttpHost proxyHost; - public FormCycleConfirmationResponse send(FormCycleFormData formData, Collection<FormcycleAttachment> attachments, Collection<FormcycleAttachment> representations) throws IOException { + public FormCycleConfirmationResponse send(FormCycleFormData formData, Collection<FormcycleAttachment> attachments, + Collection<FormcycleAttachment> representations) throws IOException { try ( var closeableHttpClient = createCloseableClient(); - var closeableResponse = closeableHttpClient.execute(buildPostRequest(formData, attachments, representations)) + var closeableResponse = closeableHttpClient.execute(buildPostRequest(formData, attachments, representations), getContext()) ) { return parseResponse(closeableResponse); } } CloseableHttpClient createCloseableClient() { - return HttpClientBuilder.create().setDefaultRequestConfig(createHttpClientConfig()).build(); + var clientBuilder = HttpClientBuilder.create().setDefaultRequestConfig(createHttpClientConfig()); + addProxy(clientBuilder); + return clientBuilder.build(); + } + + void addProxy(HttpClientBuilder httpClientBuilder) { + Optional.ofNullable(getProxyConfig()).ifPresent( + host -> configureProxy(httpClientBuilder)); + } + + void configureProxy(HttpClientBuilder httpClientBuilder) { + httpClientBuilder.setRoutePlanner(createHttpRouterPlanner()); + httpClientBuilder.setDefaultCredentialsProvider(getCredentialsProvider()); + } + + ProxyConfig getProxyConfig() { + var proxyConfig = config.getProxyConfig(); + if (isNoneBlank(proxyConfig.getHost())) { + return proxyConfig; + } + if (isNull(systemProxyConfig)) { + systemProxyConfig = loadSystemProxyConfig(); + } + return systemProxyConfig.orElse(null); + } + + Optional<ProxyConfig> loadSystemProxyConfig() { + ProxyConfig value = loadHttpsProxyConfig(); + ProxyConfig sysProxyConfig = Optional.ofNullable(value).orElseGet(this::loadHttpProxyConfig); + return Optional.ofNullable(sysProxyConfig); + } + + ProxyConfig loadHttpsProxyConfig() { + var systemProxyHost = systemPropertiesProvider.getHttpsProxyHost(); + if (isBlank(systemProxyHost)) { + return null; + } + return ProxyConfig.builder() + .host(systemProxyHost) + .port(Utils.parsePort(systemPropertiesProvider.getHttpsProxyPort())) + .user(systemPropertiesProvider.getHttpsProxyUser()) + .password(systemPropertiesProvider.getHttpsProxyPassword()) + .build(); + } + + ProxyConfig loadHttpProxyConfig() { + var systemProxyHost = systemPropertiesProvider.getHttpProxyHost(); + if (isBlank(systemProxyHost)) { + return null; + } + return ProxyConfig.builder() + .host(systemProxyHost) + .port(Utils.parsePort(systemPropertiesProvider.getHttpProxyPort())) + .user(systemPropertiesProvider.getHttpProxyUser()) + .password(systemPropertiesProvider.getHttpProxyPassword()) + .build(); + } + + HttpHost getProxyHost() { + if (isNull(proxyHost)) { + proxyHost = createProxyHost(); + } + return proxyHost; + } + + HttpHost createProxyHost() { + var proxyConfig = getProxyConfig(); + return new HttpHost(proxyConfig.getHost(), proxyConfig.getPort()); + } + + BasicCredentialsProvider getCredentialsProvider() { + if (isNull(credentialsProvider)) { + credentialsProvider = createCredentialsProvider(); + } + return credentialsProvider; + } + + BasicCredentialsProvider createCredentialsProvider() { + var basicCredentialsProvider = new BasicCredentialsProvider(); + var proxyConfig = getProxyConfig(); + basicCredentialsProvider.setCredentials(new AuthScope(getProxyHost()), + new UsernamePasswordCredentials(proxyConfig.getUser(), proxyConfig.getPassword())); + return basicCredentialsProvider; + } + + HttpRoutePlanner createHttpRouterPlanner() { + return new DefaultProxyRoutePlanner(getProxyHost()); } RequestConfig createHttpClientConfig() { @@ -65,13 +171,37 @@ public class OzgCloudFormDataHttpClient { .setSocketTimeout(HTTPCLIENT_TIMEOUT).build(); } - HttpPost buildPostRequest(FormCycleFormData formData, Collection<FormcycleAttachment> attachments, Collection<FormcycleAttachment> representations) { + HttpPost buildPostRequest(FormCycleFormData formData, Collection<FormcycleAttachment> attachments, + Collection<FormcycleAttachment> representations) { var builder = new HttpPostRequestBuilder(config).withFormData(formData); Optional.ofNullable(attachments).ifPresent(builder::withAttachments); Optional.ofNullable(representations).ifPresent(builder::withRepresentations); return builder.build(); } + HttpContext getContext() { + if (isNull(context)) { + context = createContext(); + } + return context; + } + + HttpClientContext createContext() { + var clientContext = HttpClientContext.create(); + if (nonNull(getProxyConfig())) { + clientContext.setCredentialsProvider(getCredentialsProvider()); + clientContext.setAuthCache(createAuthCache()); + } + return clientContext; + } + + BasicAuthCache createAuthCache() { + var authCache = new BasicAuthCache(); + var basicAuth = new BasicScheme(); + authCache.put(getProxyHost(), basicAuth); + return authCache; + } + FormCycleConfirmationResponse parseResponse(CloseableHttpResponse response) throws IOException { InputStream responseContent = response.getEntity().getContent(); return FormCycleConfirmationResponse.parseFrom(responseContent); diff --git a/src/main/java/de/ozgcloud/formcycle/PluginBundleProperties.java b/src/main/java/de/ozgcloud/formcycle/PluginBundleProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..bb3f81373257dfee3f913df329deb7a37276a8ff --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/PluginBundleProperties.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.formcycle; + +import static de.ozgcloud.formcycle.OzgCloudConfig.*; +import static de.ozgcloud.formcycle.ProxyConfig.*; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +import de.xima.fc.interfaces.plugin.lifecycle.helper.IPluginResourceHelper; +import de.xima.fc.plugin.config.IBundleConfigParam; +import de.xima.fc.plugin.config.IBundleProperties; +import de.xima.fc.plugin.models.config.BundleConfigGroupItem; +import de.xima.fc.plugin.models.config.BundleConfigParam; + +public class PluginBundleProperties implements IBundleProperties { + + private static final boolean CRYPTIC_VALUE = true; + private static final boolean MANDATORY = true; + private static final boolean NOT_MANDATORY = false; + + @Override + public Map<String, IBundleConfigParam> getConfigProperties(IPluginResourceHelper resHelper, Locale currentLocale) { + var configMap = new LinkedHashMap<String, IBundleConfigParam>(); + configMap.put(KEY_EINGANGSADAPTER_URL, new BundleConfigParam(KEY_EINGANGSADAPTER_URL, "", MANDATORY)); + configMap.put("proxy", new BundleConfigGroupItem("Konfiguration für den Proxy", "")); + configMap.put(KEY_PROXY_HOST, new BundleConfigParam(KEY_PROXY_HOST, "", NOT_MANDATORY)); + configMap.put(KEY_PROXY_PORT, new BundleConfigParam(KEY_PROXY_PORT, "", NOT_MANDATORY)); + configMap.put(KEY_PROXY_USER, new BundleConfigParam(KEY_PROXY_USER, "", NOT_MANDATORY)); + configMap.put(KEY_PROXY_PASSWORD, new BundleConfigParam(KEY_PROXY_PASSWORD, "", NOT_MANDATORY, CRYPTIC_VALUE)); + return Collections.unmodifiableMap(configMap); + } +} diff --git a/src/main/java/de/ozgcloud/formcycle/PluginPropertiesMapper.java b/src/main/java/de/ozgcloud/formcycle/PluginPropertiesMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..fa8a25c8a7e444562ffe5afad4ed84f4b159bd93 --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/PluginPropertiesMapper.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle; + +import static java.util.Objects.*; +import static org.apache.commons.lang3.StringUtils.*; + +import java.util.Properties; + +import de.ozgcloud.formcycle.errorhandling.UserErrorDispatcher; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class PluginPropertiesMapper { + + private final UserErrorDispatcher userErrorDispatcher; + + public OzgCloudConfig mapProperties(Properties pluginProperties) { + if (isNull(pluginProperties) || pluginProperties.isEmpty()) { + return OzgCloudConfig.builder().build(); + } + return OzgCloudConfig.builder() + .eingangsAdapterUrl(pluginProperties.getProperty(OzgCloudConfig.KEY_EINGANGSADAPTER_URL)) + .proxyConfig(mapProxyProperties(pluginProperties)) + .build(); + } + + public ProxyConfig mapProxyProperties(Properties pluginProperties) { + return ProxyConfig.builder() + .host(pluginProperties.getProperty(ProxyConfig.KEY_PROXY_HOST)) + .port(getPort(pluginProperties)) + .user(pluginProperties.getProperty(ProxyConfig.KEY_PROXY_USER)) + .password(pluginProperties.getProperty(ProxyConfig.KEY_PROXY_PASSWORD)) + .build(); + } + + Integer getPort(Properties pluginProperties) { + var portProperty = pluginProperties.getProperty(ProxyConfig.KEY_PROXY_PORT); + if (isBlank(portProperty)) { + return null; + } + var port = Utils.parsePort(portProperty); + if (isNull(port)) { + userErrorDispatcher.sendWrongProxyPortFormatMessage(); + } + return port; + } + +} diff --git a/src/main/java/de/ozgcloud/formcycle/ProxyConfig.java b/src/main/java/de/ozgcloud/formcycle/ProxyConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..97c8bdcb186ca49662e4fe384ee77ddd5e2df5ce --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/ProxyConfig.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle; + +import java.io.Serializable; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ProxyConfig implements Serializable { + + private static final long serialVersionUID = 1L; + + public static final String KEY_PROXY_HOST = "proxyHost"; + public static final String KEY_PROXY_PORT = "proxyPort"; + public static final String KEY_PROXY_USER = "proxyUser"; + public static final String KEY_PROXY_PASSWORD = "proxyPassword"; + + public static final String KEY_HTTP_PROXY_HOST = "http.proxyHost"; + public static final String KEY_HTTP_PROXY_PORT = "http.proxyPort"; + public static final String KEY_HTTP_PROXY_USER = "http.proxyUser"; + public static final String KEY_HTTP_PROXY_PASSWORD = "http.proxyPassword"; + + public static final String KEY_HTTPS_PROXY_HOST = "https.proxyHost"; + public static final String KEY_HTTPS_PROXY_PORT = "https.proxyPort"; + public static final String KEY_HTTPS_PROXY_USER = "https.proxyUser"; + public static final String KEY_HTTPS_PROXY_PASSWORD = "https.proxyPassword"; + + private String host; + private Integer port; + private String user; + private String password; + +} diff --git a/src/main/java/de/ozgcloud/formcycle/SystemPropertiesProvider.java b/src/main/java/de/ozgcloud/formcycle/SystemPropertiesProvider.java new file mode 100644 index 0000000000000000000000000000000000000000..eef336cf1ccf1128b9c0cadf3b564741adb1ad92 --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/SystemPropertiesProvider.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle; + +public class SystemPropertiesProvider { + + public String getHttpsProxyHost() { + return System.getProperty(ProxyConfig.KEY_HTTPS_PROXY_HOST); + } + + public String getHttpsProxyPort() { + return System.getProperty(ProxyConfig.KEY_HTTPS_PROXY_PORT); + } + + public String getHttpsProxyUser() { + return System.getProperty(ProxyConfig.KEY_HTTPS_PROXY_USER); + } + + public String getHttpsProxyPassword() { + return System.getProperty(ProxyConfig.KEY_HTTPS_PROXY_PASSWORD); + } + + public String getHttpProxyHost() { + return System.getProperty(ProxyConfig.KEY_HTTP_PROXY_HOST); + } + + public String getHttpProxyPort() { + return System.getProperty(ProxyConfig.KEY_HTTP_PROXY_PORT); + } + + public String getHttpProxyUser() { + return System.getProperty(ProxyConfig.KEY_HTTP_PROXY_USER); + } + + public String getHttpProxyPassword() { + return System.getProperty(ProxyConfig.KEY_HTTP_PROXY_PASSWORD); + } +} diff --git a/src/main/java/de/ozgcloud/formcycle/Utils.java b/src/main/java/de/ozgcloud/formcycle/Utils.java new file mode 100644 index 0000000000000000000000000000000000000000..6811cb2fd299332479d1371d9bf244289bc67121 --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/Utils.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.formcycle; + +import static org.apache.commons.lang3.StringUtils.*; + +import java.util.Optional; +import java.util.regex.Pattern; + +import lombok.NoArgsConstructor; + +@NoArgsConstructor(access = lombok.AccessLevel.PRIVATE) +public class Utils { + + private static final Pattern PORT_PATTERN = Pattern.compile("\\s*\\d{1,5}\\s*"); + + public static Integer parsePort(String portString) { + if (isBlank(portString) || !PORT_PATTERN.matcher(portString).matches()) { + return null; + } + return Optional.of(Integer.parseInt(portString.trim())).filter(port -> port > 0 && port < 65536).orElse(null); + } +} diff --git a/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodePlugin.java b/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodePlugin.java index 22550d0472bdedb65bb9ea1c510f9c714cb5bd31..bd981658f57e658a377dd0316cb3dacbe1f62423 100644 --- a/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodePlugin.java +++ b/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodePlugin.java @@ -33,6 +33,7 @@ import de.ozgcloud.formcycle.attachment.AttachmentMapper; import de.ozgcloud.formcycle.errorhandling.EWorkflowElementNodeError; import de.ozgcloud.formcycle.errorhandling.EWorkflowElementNodeSoftError; import de.ozgcloud.formcycle.errorhandling.NodeThrewExceptionFactory; +import de.ozgcloud.formcycle.errorhandling.UserErrorDispatcher; import de.ozgcloud.formcycle.formdata.OzgCloudFormDataMapper; import de.ozgcloud.formcycle.formdata.PluginFormDataAdapter; import de.xima.fc.beans.interfaces.IGuiIcon; @@ -65,10 +66,16 @@ public final class WorkflowElementNodePlugin implements IPluginActionNodeHandler<WorkflowElementNodeProps>, IKeyValueSummarizableNode<WorkflowElementNodeProps> { private transient IPluginInitializeData initializeData; + private OzgCloudConfig ozgCloudConfig; @Override public void initialize(IPluginInitializeData initializeData) { this.initializeData = initializeData; + this.ozgCloudConfig = createPropertiesMapper().mapProperties(initializeData.getProperties()); + } + + PluginPropertiesMapper createPropertiesMapper() { + return new PluginPropertiesMapper(new UserErrorDispatcher()); } @Override @@ -177,20 +184,22 @@ public final class WorkflowElementNodePlugin @Override public INormalCompletionResult execute(INodeExecutionParams<WorkflowElementNodeProps> params) throws AbstractAbruptCompletionException { - var ozgFormDataHttpClient = new OzgCloudFormDataHttpClient( - OzgCloudConfig.builder().eingangsAdapterUrl(params.getData().getEingangsAdapterUrl()).build()); var workflowExecutionEnvironmentData = params.getWorkflowContext().env(); PluginFormDataAdapter pluginFormDataAdapter = new PluginFormDataAdapter(workflowExecutionEnvironmentData, params.getData().getOrganisationsEinheitId()); var ozgCloudFormDataMapper = new OzgCloudFormDataMapper(); var exceptionFactory = new NodeThrewExceptionFactory(params.throwingException()); var attachmentsAdapter = new AttachmentMapper(exceptionFactory); - var pluginExecutor = new WorkflowElementNodeExecutor(ozgCloudFormDataMapper, ozgFormDataHttpClient, exceptionFactory, attachmentsAdapter, - pluginFormDataAdapter, createAttachmentSupplier(workflowExecutionEnvironmentData)); + var pluginExecutor = new WorkflowElementNodeExecutor(ozgCloudFormDataMapper, createOzgClient(), exceptionFactory, + attachmentsAdapter, pluginFormDataAdapter, createAttachmentSupplier(workflowExecutionEnvironmentData)); var executionResult = pluginExecutor.execute(); return params.normalResult().success(executionResult.get()).build(); } + private OzgCloudFormDataHttpClient createOzgClient() { + return new OzgCloudFormDataHttpClient(ozgCloudConfig, new SystemPropertiesProvider()); + } + private Supplier<List<Attachment>> createAttachmentSupplier(IWorkflowExecutionEnvironmentData environmentData) { return () -> Optional.ofNullable(environmentData.getFormRecord().getAttachments()).orElse(List.of()); } @@ -218,4 +227,5 @@ public final class WorkflowElementNodePlugin public IPluginInitializeData getPluginInitializeData() { return initializeData; } + } diff --git a/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodeProps.java b/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodeProps.java index 829a996bc69489c647096a1319f7bbf375693378..973eac037c3b4f336e7fabef99d3146bc81fcda3 100644 --- a/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodeProps.java +++ b/src/main/java/de/ozgcloud/formcycle/WorkflowElementNodeProps.java @@ -50,10 +50,6 @@ import lombok.Setter; @Setter public final class WorkflowElementNodeProps extends BaseActionProps { - @NotEmpty - @Size(max = 100) - private String eingangsAdapterUrl; - @NotEmpty @Size(max = 20) private String organisationsEinheitId; diff --git a/src/main/java/de/ozgcloud/formcycle/errorhandling/UserErrorDispatcher.java b/src/main/java/de/ozgcloud/formcycle/errorhandling/UserErrorDispatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..f71e3c7be6031d638eead686c4136f54e249cb76 --- /dev/null +++ b/src/main/java/de/ozgcloud/formcycle/errorhandling/UserErrorDispatcher.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle.errorhandling; + +import java.util.Optional; + +import javax.faces.context.FacesContext; + +import org.omnifaces.util.Messages; + +import de.ozgcloud.formcycle.ProxyConfig; + +public class UserErrorDispatcher { + + static final String PORT_FORMAT_ERROR_MESSAGE = "\"{0}\" hat ein falsches Format"; + static final String PORT_FORMAT_ERROR_DESCRIPTION = "Port muss eine Zahl zwischen 1 und 65535 sein"; + + public void sendWrongProxyPortFormatMessage() { + Optional.ofNullable(FacesContext.getCurrentInstance()) + .ifPresent(ctx -> Messages.create(PORT_FORMAT_ERROR_MESSAGE, ProxyConfig.KEY_PROXY_PORT).detail(PORT_FORMAT_ERROR_DESCRIPTION).error() + .add()); + } + +} diff --git a/src/main/resources/WEB-INF/ui/WorkflowElementNode.xhtml b/src/main/resources/WEB-INF/ui/WorkflowElementNode.xhtml index 6f880646d4468f22abbe654dd4ddb9a4c9cc75af..bc38815fb277e705f99a062025ffc000cf325481 100644 --- a/src/main/resources/WEB-INF/ui/WorkflowElementNode.xhtml +++ b/src/main/resources/WEB-INF/ui/WorkflowElementNode.xhtml @@ -19,13 +19,6 @@ <p:fieldset legend="#{msg['WorkflowElementNodeProps.section_settings']}" styleClass="fc-fieldset"> - <xi:inputText id="eingangsAdapterUrl" value="#{model.eingangsAdapterUrl}" - forceIndicateRequired="true" - label="#{msg['WorkflowElementNodeProps.eingangsAdapterUrl']}"> - <p:ajax event="change" partialSubmit="true" - listener="#{elementPropertiesBean.storeCurrent}" process="@this" - update=":flowchartForm:flowchart" global="false" /> - </xi:inputText> <xi:inputText id="organisationsEinheitId" value="#{model.organisationsEinheitId}" forceIndicateRequired="true" label="#{msg['WorkflowElementNodeProps.organisationsEinheitId']}"> diff --git a/src/test/java/de/ozgcloud/formcycle/HttpPostRequestBuilderTest.java b/src/test/java/de/ozgcloud/formcycle/HttpPostRequestBuilderTest.java index 9f0124bcc0d6288f1d302e1ed2c7da52de7ee9d0..3f840ebc7baf78aa806292475d25f8ed8c73c1ab 100644 --- a/src/test/java/de/ozgcloud/formcycle/HttpPostRequestBuilderTest.java +++ b/src/test/java/de/ozgcloud/formcycle/HttpPostRequestBuilderTest.java @@ -42,6 +42,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Spy; import de.itvsh.kop.eingangsadapter.formcycle.FormCycleFormData; import de.ozgcloud.formcycle.attachment.FormcycleAttachmentTestFactory; @@ -49,6 +50,9 @@ import lombok.SneakyThrows; class HttpPostRequestBuilderTest { + static final String TARGET_URL = "http://url"; + + @Spy @InjectMocks private HttpPostRequestBuilder requestBuilder; @@ -146,7 +150,6 @@ class HttpPostRequestBuilderTest { @Nested class TestBuildPostRequest { - private static final String TARGET_URL = "url"; @BeforeEach void setup() { @@ -155,9 +158,12 @@ class HttpPostRequestBuilderTest { @Test void shouldSetTargetUrl() { + var expectedUrl = TARGET_URL + "/" + HttpPostRequestBuilder.FORMCYCLE_ENDPOINT; + when(cloudConfig.getEingangsAdapterUrl()).thenReturn(TARGET_URL); + var httpPost = requestBuilder.build(); - assertThat(httpPost.getURI()).isEqualTo(URI.create(TARGET_URL)); + assertThat(httpPost.getURI()).isEqualTo(URI.create(expectedUrl)); } @Test @@ -170,4 +176,37 @@ class HttpPostRequestBuilderTest { assertThat(httpPost.getEntity()).isEqualTo(expectedHttpEntity); } } + + @Nested + class TestBuildEingangsAdapterUrl { + + @Test + void shouldAddEndpointWithSlash() { + when(cloudConfig.getEingangsAdapterUrl()).thenReturn(TARGET_URL); + + var url = requestBuilder.buildEingagsAdapterUrl(); + + assertThat(url).isEqualTo(TARGET_URL + "/" + HttpPostRequestBuilder.FORMCYCLE_ENDPOINT); + } + + @Test + void shouldAddEndpoint() { + var expectedUrl = TARGET_URL + "url/"; + when(cloudConfig.getEingangsAdapterUrl()).thenReturn(expectedUrl); + + var url = requestBuilder.buildEingagsAdapterUrl(); + + assertThat(url).isEqualTo(expectedUrl + HttpPostRequestBuilder.FORMCYCLE_ENDPOINT); + } + + @Test + void shouldAcceptUrlWithEndpoint() { + var expectedUrl = TARGET_URL + "/" + HttpPostRequestBuilder.FORMCYCLE_ENDPOINT; + when(cloudConfig.getEingangsAdapterUrl()).thenReturn(expectedUrl); + + var url = requestBuilder.buildEingagsAdapterUrl(); + + assertThat(url).isEqualTo(expectedUrl); + } + } } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/formcycle/OzgCloudConfigTestFactory.java b/src/test/java/de/ozgcloud/formcycle/OzgCloudConfigTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..95bf6169d5651be19e3b414bbd9d97bc16c38d5e --- /dev/null +++ b/src/test/java/de/ozgcloud/formcycle/OzgCloudConfigTestFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.formcycle; + +import de.ozgcloud.formcycle.OzgCloudConfig.OzgCloudConfigBuilder; + +public class OzgCloudConfigTestFactory { + + public static final ProxyConfig proxyConfig = ProxyConfigTestFactory.create(); + public static OzgCloudConfig create() { + return createBuilder().build(); + } + + public static OzgCloudConfigBuilder createBuilder() { + return OzgCloudConfig.builder() + .eingangsAdapterUrl(PropertiesTestFactory.EINGANGSADAPTER_URL) + .proxyConfig(proxyConfig); + } +} diff --git a/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientITCase.java b/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientITCase.java index b19f8fbade3860fef52165bf3985368a4ff9256b..5b463a3399bbd5997f854116d9211a32aba409f5 100644 --- a/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientITCase.java +++ b/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientITCase.java @@ -51,7 +51,7 @@ class OzgCloudFormDataHttpClientITCase { String url = "https://fuerth-formcycle.dev.by.kop-cloud.de/formData"; OzgCloudFormDataHttpClient client = new OzgCloudFormDataHttpClient(OzgCloudConfig.builder() - .eingangsAdapterUrl(url).build()); + .eingangsAdapterUrl(url).build(), new SystemPropertiesProvider()); FormCycleConfirmationResponse response = client.send(createTestFormData(), Collections.emptyList(), Collections.emptyList()); diff --git a/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientTest.java b/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientTest.java index 67931ee9e11f086ce2f9c0590e22e4720e50ab0e..bf92bb588bd208ad2578dcab1a754666b5e02548 100644 --- a/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientTest.java +++ b/src/test/java/de/ozgcloud/formcycle/OzgCloudFormDataHttpClientTest.java @@ -26,18 +26,29 @@ import static de.ozgcloud.formcycle.OzgCloudFormDataHttpClient.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import java.lang.reflect.Field; import java.util.List; +import java.util.Optional; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.conn.routing.HttpRoutePlanner; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.protocol.HttpContext; +import org.apache.logging.log4j.core.util.ReflectionUtil; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; -import org.mockito.Spy; +import org.springframework.util.ReflectionUtils; import de.itvsh.kop.eingangsadapter.formcycle.FormCycleFormData; import de.ozgcloud.formcycle.attachment.FormcycleAttachment; @@ -46,36 +57,42 @@ import lombok.SneakyThrows; class OzgCloudFormDataHttpClientTest { - @Spy - @InjectMocks - private OzgCloudFormDataHttpClient client; - + @Mock + private SystemPropertiesProvider systemPropertiesProvider; @Mock private FormCycleFormData formData; @Mock private CloseableHttpClient httpClient; @Mock - private OzgCloudConfig cloudConfig; - @Mock private CloseableHttpResponse closeableHttpResponse; private List<FormcycleAttachment> attachments; private List<FormcycleAttachment> representations; + private OzgCloudFormDataHttpClient client; + + @BeforeEach + void setup() { + client = createOzgClient(OzgCloudConfigTestFactory.proxyConfig); + } + + private OzgCloudFormDataHttpClient createOzgClient(ProxyConfig proxyConfig) { + return spy(new OzgCloudFormDataHttpClient(OzgCloudConfigTestFactory.createBuilder() + .proxyConfig(proxyConfig).build(), systemPropertiesProvider)); + } + @Nested class TestSendData { - @SneakyThrows @BeforeEach void setup() { - when(cloudConfig.getEingangsAdapterUrl()).thenReturn("url"); when(formData.toByteArray()).thenReturn(new byte[] {}); attachments = List.of(FormcycleAttachmentTestFactory.create()); representations = List.of(FormcycleAttachmentTestFactory.create()); - when(closeableHttpResponse.getEntity()).thenReturn(mock(HttpEntity.class)); - when(httpClient.execute(any())).thenReturn(closeableHttpResponse); + when(closeableHttpResponse.getEntity()).thenReturn(mock(HttpEntity.class)); + when(httpClient.execute(any(), any(HttpContext.class))).thenReturn(closeableHttpResponse); doReturn(httpClient).when(client).createCloseableClient(); } @@ -94,7 +111,7 @@ class OzgCloudFormDataHttpClientTest { client.send(formData, attachments, representations); verify(client).createCloseableClient(); - verify(httpClient).execute(any()); + verify(httpClient).execute(any(), any(HttpContext.class)); } @SneakyThrows @@ -132,5 +149,310 @@ class OzgCloudFormDataHttpClientTest { assertThat(httpClientConfig.getSocketTimeout()).isEqualTo(HTTPCLIENT_TIMEOUT); } + + } + + @Nested + class TestCreateCloseableClient { + + @Test + void shouldCallCreateHttpClientConfig() { + client.createCloseableClient(); + + verify(client).createHttpClientConfig(); + } + + @Test + void shouldCallAddProxy() { + client.createCloseableClient(); + + verify(client).addProxy(any()); + } + + @Test + void shouldCreateClient() { + var httpClient = client.createCloseableClient(); + + assertThat(httpClient).isNotNull(); + } + } + + @Nested + class TestAddProxy { + + @Mock + private HttpClientBuilder httpClientBuilder; + + @Test + void shouldCallConfigureProxy() { + client.addProxy(httpClientBuilder); + + verify(client).configureProxy(httpClientBuilder); + } + } + + @Nested + class TestConfigureProxy { + + @Mock + private HttpClientBuilder httpClientBuilder; + + @Test + void shouldCallSetRouterPlanner() { + var routePlanner = mock(HttpRoutePlanner.class); + doReturn(routePlanner).when(client).createHttpRouterPlanner(); + + client.configureProxy(httpClientBuilder); + + verify(httpClientBuilder).setRoutePlanner(routePlanner); + } + + @Test + void shouldCallSetCredentialProvider() { + var credentialsProvider = mock(BasicCredentialsProvider.class); + doReturn(credentialsProvider).when(client).getCredentialsProvider(); + + client.configureProxy(httpClientBuilder); + + verify(httpClientBuilder).setDefaultCredentialsProvider(credentialsProvider); + } + } + + @Nested + class TestGetProxyConfig { + + @Test + void shouldReturnFromOzgCloudConfig() { + var proxyConfig = client.getProxyConfig(); + + assertThat(proxyConfig).isEqualTo(OzgCloudConfigTestFactory.proxyConfig); + } + + @Test + void shouldCallLoadSystemProxyConfig() { + client = createOzgClient(ProxyConfigTestFactory.createEmpty()); + + client.getProxyConfig(); + + verify(client).loadSystemProxyConfig(); + } + + @Test + void shouldReturnNullWhenNoProxy() { + client = createOzgClient(ProxyConfigTestFactory.createEmpty()); + doReturn(Optional.empty()).when(client).loadSystemProxyConfig(); + + var proxyConfig = client.getProxyConfig(); + + assertThat(proxyConfig).isNull(); + } + + } + + @Nested + class TestLoadSystemProxyConfig { + + @Test + void shouldCallLoadHttpsProxyConfig() { + doReturn(ProxyConfigTestFactory.create()).when(client).loadHttpsProxyConfig(); + + client.loadSystemProxyConfig(); + + verify(client).loadHttpsProxyConfig(); + } + + @Test + @DisplayName("should not load http settings when https is set") + void shouldNotLoadHttpWhenHttps() { + doReturn(ProxyConfigTestFactory.create()).when(client).loadHttpsProxyConfig(); + + client.loadSystemProxyConfig(); + + verify(client, never()).loadHttpProxyConfig(); + } + + @Test + void shouldCallLoadHttpProxyConfig() { + doReturn(null).when(client).loadHttpsProxyConfig(); + + client.loadSystemProxyConfig(); + + verify(client).loadHttpProxyConfig(); + } + } + + @Nested + class TestLoadHttpsProxyConfig { + + @BeforeEach + void setup() { + when(systemPropertiesProvider.getHttpsProxyHost()).thenReturn(PropertiesTestFactory.PROXY_HOST); + } + + @ParameterizedTest(name = "should return null when \"{0}\"") + @NullSource + @ValueSource(strings = { "", " " }) + void shouldReturnNull(String property) { + lenient().when(systemPropertiesProvider.getHttpsProxyHost()).thenReturn(property); + + var proxyConfig = client.loadHttpsProxyConfig(); + + assertThat(proxyConfig).isNull(); + } + + @Test + void shouldSetProxyHost() { + when(systemPropertiesProvider.getHttpsProxyHost()).thenReturn(PropertiesTestFactory.PROXY_HOST); + + var proxyConfig = client.loadHttpsProxyConfig(); + + assertThat(proxyConfig.getHost()).isEqualTo(PropertiesTestFactory.PROXY_HOST); + } + + @Test + void shouldSetProxyPort() { + when(systemPropertiesProvider.getHttpsProxyPort()).thenReturn(PropertiesTestFactory.PROXY_PORT); + + var proxyConfig = client.loadHttpsProxyConfig(); + + assertThat(proxyConfig.getPort()).isEqualTo(ProxyConfigTestFactory.PROXY_PORT); + } + + + @Test + void shouldSetProxyUser() { + when(systemPropertiesProvider.getHttpsProxyUser()).thenReturn(PropertiesTestFactory.PROXY_USER); + + var proxyConfig = client.loadHttpsProxyConfig(); + + assertThat(proxyConfig.getUser()).isEqualTo(PropertiesTestFactory.PROXY_USER); + } + + @Test + void shouldSetProxyPassword() { + when(systemPropertiesProvider.getHttpsProxyPassword()).thenReturn(PropertiesTestFactory.PROXY_PASSWORD); + + var proxyConfig = client.loadHttpsProxyConfig(); + + assertThat(proxyConfig.getPassword()).isEqualTo(PropertiesTestFactory.PROXY_PASSWORD); + } + } + + @Nested + class TestLoadHttpProxyConfig { + + @BeforeEach + void setup() { + when(systemPropertiesProvider.getHttpProxyHost()).thenReturn(PropertiesTestFactory.PROXY_HOST); + } + + @ParameterizedTest(name = "should return null when \"{0}\"") + @NullSource + @ValueSource(strings = { "", " " }) + void shouldReturnNull(String property) { + lenient().when(systemPropertiesProvider.getHttpProxyHost()).thenReturn(property); + + var proxyConfig = client.loadHttpProxyConfig(); + + assertThat(proxyConfig).isNull(); + } + + @Test + void shouldSetProxyHost() { + + var proxyConfig = client.loadHttpProxyConfig(); + + assertThat(proxyConfig.getHost()).isEqualTo(PropertiesTestFactory.PROXY_HOST); + } + + @Test + void shouldSetProxyPort() { + when(systemPropertiesProvider.getHttpProxyPort()).thenReturn(PropertiesTestFactory.PROXY_PORT); + + var proxyConfig = client.loadHttpProxyConfig(); + + assertThat(proxyConfig.getPort()).isEqualTo(ProxyConfigTestFactory.PROXY_PORT); + } + + @Test + void shouldSetProxyUser() { + when(systemPropertiesProvider.getHttpProxyUser()).thenReturn(PropertiesTestFactory.PROXY_USER); + + var proxyConfig = client.loadHttpProxyConfig(); + + assertThat(proxyConfig.getUser()).isEqualTo(PropertiesTestFactory.PROXY_USER); + } + + @Test + void shouldSetProxyPassword() { + when(systemPropertiesProvider.getHttpProxyPassword()).thenReturn(PropertiesTestFactory.PROXY_PASSWORD); + + var proxyConfig = client.loadHttpProxyConfig(); + + assertThat(proxyConfig.getPassword()).isEqualTo(PropertiesTestFactory.PROXY_PASSWORD); + } + } + + @Nested + class TestGetContext { + + @Mock + private HttpClientContext context; + + @Test + void shouldReturnCreatedContext() { + doReturn(context).when(client).createContext(); + + var result = client.getContext(); + + assertThat(result).isEqualTo(context); + } + + @Test + void shouldReturnCachedContext() { + ReflectionUtil.setFieldValue(getField("context"), client, context); + + var result = client.getContext(); + + assertThat(result).isEqualTo(context); + } + + @Nested + class TestCreateContext { + + @Test + void shouldSetCredentialsProvider() { + var credentialsProvider = mock(BasicCredentialsProvider.class); + doReturn(credentialsProvider).when(client).getCredentialsProvider(); + + var result = client.createContext(); + + assertThat(result.getCredentialsProvider()).isEqualTo(credentialsProvider); + } + + @Test + void shouldCallCreateAuthCache() { + var authCache = mock(BasicAuthCache.class); + doReturn(authCache).when(client).createAuthCache(); + + var result = client.createContext(); + + assertThat(result.getAuthCache()).isEqualTo(authCache); + } + + @Test + void shouldReturnEmptyContext() { + doReturn(null).when(client).getProxyConfig(); + + client.createContext(); + + verify(client, never()).getCredentialsProvider(); + verify(client, never()).createAuthCache(); + } + } + } + + private Field getField(String name) { + return ReflectionUtils.findField(OzgCloudFormDataHttpClient.class, name); } } \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/formcycle/PluginPropertiesMapperTest.java b/src/test/java/de/ozgcloud/formcycle/PluginPropertiesMapperTest.java new file mode 100644 index 0000000000000000000000000000000000000000..618cc58be145343b130034aad1af4ec456faa8dd --- /dev/null +++ b/src/test/java/de/ozgcloud/formcycle/PluginPropertiesMapperTest.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle; + +import static de.ozgcloud.formcycle.PropertiesTestFactory.*; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.Properties; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mock; + +import de.ozgcloud.formcycle.errorhandling.UserErrorDispatcher; + +class PluginPropertiesMapperTest { + + private PluginPropertiesMapper mapper; + + @Mock + private UserErrorDispatcher userErrorDispatcher; + + private Properties properties = PropertiesTestFactory.create(); + + @BeforeEach + void setUp() { + mapper = spy(new PluginPropertiesMapper(userErrorDispatcher)); + } + + @Nested + class TestMapProperties { + + @Test + void shouldAcceptNull() { + var result = mapper.mapProperties(null); + + assertThat(result.getEingangsAdapterUrl()).isNull(); + assertThat(result.getProxyConfig()).isNull(); + } + + @Test + void shouldAcceptEmptyProperties() { + var result = mapper.mapProperties(createEmpty()); + + assertThat(result.getEingangsAdapterUrl()).isNull(); + assertThat(result.getProxyConfig()).isNull(); + } + + @Test + void shouldSetEingangsAdapterUrl() { + var result = mapper.mapProperties(properties); + + assertThat(result.getEingangsAdapterUrl()).isEqualTo(EINGANGSADAPTER_URL); + } + + @Test + void shouldCallMapProxyProperties() { + mapper.mapProxyProperties(properties); + + verify(mapper).mapProxyProperties(properties); + } + } + + @Nested + class TestMapProxyProperty { + + @Test + void shouldSetHost() { + var result = mapper.mapProxyProperties(properties); + + assertThat(result.getHost()).isEqualTo(PROXY_HOST); + } + + @Test + void shouldSetPort(){ + doReturn(1).when(mapper).getPort(any()); + + var result = mapper.mapProxyProperties(properties); + + assertThat(result.getPort()).isEqualTo(1); + } + + @Test + void shouldSetUser() { + var result = mapper.mapProxyProperties(properties); + + assertThat(result.getUser()).isEqualTo(PROXY_USER); + } + + @Test + void shouldSetPassword() { + var result = mapper.mapProxyProperties(properties); + + assertThat(result.getPassword()).isEqualTo(PROXY_PASSWORD); + } + + } + + @Nested + class TestGetPort { + + @DisplayName("should send user error message when") + @ParameterizedTest(name = "port property is {0}") + @ValueSource(strings = {"0", "65536", "abs"}) + void shouldSendUserErrorMessage(String portProperty) { + mapper.getPort(createPortProperty(portProperty)); + + verify(userErrorDispatcher).sendWrongProxyPortFormatMessage(); + } + + @Test + void shouldReturnPort() { + var result = mapper.getPort(create()); + + assertThat(result).isEqualTo(1); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/formcycle/PropertiesTestFactory.java b/src/test/java/de/ozgcloud/formcycle/PropertiesTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..aa6caf0cfa281471f03ae788aca0dddae5ea1fe5 --- /dev/null +++ b/src/test/java/de/ozgcloud/formcycle/PropertiesTestFactory.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ + +package de.ozgcloud.formcycle; + +import java.util.Properties; + +public class PropertiesTestFactory { + + public static final String EINGANGSADAPTER_URL = "url"; + public static final String PROXY_HOST = "host"; + public static final String PROXY_PORT = "1"; + public static final String PROXY_USER = "user"; + public static final String PROXY_PASSWORD = "password"; + + public static Properties createEmpty() { + return new Properties(); + } + public static Properties create() { + var properties = createEmpty(); + properties.setProperty(OzgCloudConfig.KEY_EINGANGSADAPTER_URL, EINGANGSADAPTER_URL); + properties.setProperty(ProxyConfig.KEY_PROXY_HOST, PROXY_HOST); + properties.setProperty(ProxyConfig.KEY_PROXY_PORT, PROXY_PORT); + properties.setProperty(ProxyConfig.KEY_PROXY_USER, PROXY_USER); + properties.setProperty(ProxyConfig.KEY_PROXY_PASSWORD, PROXY_PASSWORD); + return properties; + } + + public static Properties createPortProperty(String port) { + var properties = createEmpty(); + properties.setProperty(ProxyConfig.KEY_PROXY_PORT, port); + return properties; + } +} diff --git a/src/test/java/de/ozgcloud/formcycle/ProxyConfigTestFactory.java b/src/test/java/de/ozgcloud/formcycle/ProxyConfigTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..ff4f389516a475205f31565174eecc96a5cc4cf5 --- /dev/null +++ b/src/test/java/de/ozgcloud/formcycle/ProxyConfigTestFactory.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.formcycle; + +public class ProxyConfigTestFactory { + + public static final Integer PROXY_PORT = Integer.parseInt(PropertiesTestFactory.PROXY_PORT); + + public static ProxyConfig createEmpty() { + return createBuilder().host("").port(null).user("").password("").build(); + } + + public static ProxyConfig create() { + return createBuilder().build(); + } + + public static ProxyConfig.ProxyConfigBuilder createBuilder() { + return ProxyConfig.builder() + .host(PropertiesTestFactory.PROXY_HOST) + .port(PROXY_PORT) + .user(PropertiesTestFactory.PROXY_USER) + .password(PropertiesTestFactory.PROXY_PASSWORD); + } +} diff --git a/src/test/java/de/ozgcloud/formcycle/UtilsTest.java b/src/test/java/de/ozgcloud/formcycle/UtilsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..96b8741289c6f23532e25337d4c0cd7cae36963e --- /dev/null +++ b/src/test/java/de/ozgcloud/formcycle/UtilsTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2023 Das Land Schleswig-Holstein vertreten durch das + * Ministerium für Energiewende, Klimaschutz, Umwelt und Natur + * Zentrales IT-Management + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +package de.ozgcloud.formcycle; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +class UtilsTest { + + @DisplayName("should return null when") + @ParameterizedTest(name = "port property is \"{0}\"") + @NullSource + @ValueSource(strings = {"", "0", "65536", "abs"}) + void shouldReturnNull(String portProperty) { + var result = Utils.parsePort(portProperty); + + assertThat(result).isNull(); + } + + @Test + void shouldReturnPort() { + var result = Utils.parsePort("1"); + + assertThat(result).isEqualTo(1); + } + +} \ No newline at end of file diff --git a/src/test/java/de/ozgcloud/formcycle/WorkflowElementNodePluginTest.java b/src/test/java/de/ozgcloud/formcycle/WorkflowElementNodePluginTest.java index 86d0be9ca5936f69b261fc82bea2fc1fbaae0eb5..d20cd5714a9e08e86b1544e7cbf537da23bd2cad 100644 --- a/src/test/java/de/ozgcloud/formcycle/WorkflowElementNodePluginTest.java +++ b/src/test/java/de/ozgcloud/formcycle/WorkflowElementNodePluginTest.java @@ -7,7 +7,9 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.Spy; +import de.xima.fc.interfaces.plugin.lifecycle.IPluginInitializeData; import de.xima.fc.interfaces.workflow.value.IRecordValueDescriptorBuilder; import de.xima.fc.interfaces.workflow.value.IStringValueDescriptor; import de.xima.fc.interfaces.workflow.value.IValueDescriptor; @@ -15,8 +17,40 @@ import de.xima.fc.interfaces.workflow.value.IValueDescriptorFactory; class WorkflowElementNodePluginTest { + @Spy private WorkflowElementNodePlugin plugin = new WorkflowElementNodePlugin(); + @Nested + class TestInitialization { + + @Mock + private IPluginInitializeData initializeData; + @Mock + private PluginPropertiesMapper propertiesMapper; + + @BeforeEach + void setup() { + when(plugin.createPropertiesMapper()).thenReturn(propertiesMapper); + } + + @Test + void shouldCallCreatePropertiesMapper() { + plugin.initialize(initializeData); + + verify(plugin).createPropertiesMapper(); + } + + @Test + void shouldCallMapProperties() { + var properties = PropertiesTestFactory.create(); + when(initializeData.getProperties()).thenReturn(properties); + + plugin.initialize(initializeData); + + verify(propertiesMapper).mapProperties(properties); + } + } + @Nested @DisplayName("Success value descriptor") class TestSuccessValueDescriptor {