This is an automated email from the ASF dual-hosted git repository. orpiske pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new 24a16a8239b CAMEL-19997: initial implementation of a Server Message Block (SMB) component 24a16a8239b is described below commit 24a16a8239b4d9290083fd1a352973ba80a8c633 Author: Otavio Rodolfo Piske <angusyo...@gmail.com> AuthorDate: Thu Oct 19 14:04:19 2023 +0200 CAMEL-19997: initial implementation of a Server Message Block (SMB) component --- bom/camel-bom/pom.xml | 5 + catalog/camel-allcomponents/pom.xml | 5 + .../org/apache/camel/catalog/components.properties | 1 + .../org/apache/camel/catalog/components/smb.json | 45 ++++++++ components/camel-smb/pom.xml | 78 ++++++++++++++ .../component/smb/SmbComponentConfigurer.java | 61 +++++++++++ .../camel/component/smb/SmbEndpointConfigurer.java | 97 +++++++++++++++++ .../camel/component/smb/SmbEndpointUriFactory.java | 83 +++++++++++++++ .../services/org/apache/camel/component.properties | 7 ++ .../services/org/apache/camel/component/smb | 2 + .../org/apache/camel/configurer/smb-component | 2 + .../org/apache/camel/configurer/smb-endpoint | 2 + .../org/apache/camel/urifactory/smb-endpoint | 2 + .../org/apache/camel/component/smb/smb.json | 45 ++++++++ .../camel-smb/src/main/docs/smb-component.adoc | 57 ++++++++++ .../apache/camel/component/smb/SmbComponent.java | 68 ++++++++++++ .../camel/component/smb/SmbConfiguration.java | 110 ++++++++++++++++++++ .../apache/camel/component/smb/SmbConsumer.java | 86 +++++++++++++++ .../apache/camel/component/smb/SmbEndpoint.java | 115 +++++++++++++++++++++ .../org/apache/camel/component/smb/SmbIOBean.java | 65 ++++++++++++ .../apache/camel/component/smb/SmbReadBean.java | 55 ++++++++++ .../services/org/apache/camel/component/smb | 1 + .../apache/camel/component/smb/SmbComponentIT.java | 68 ++++++++++++ .../camel-smb/src/test/resources/log4j2.properties | 35 +++++++ components/pom.xml | 1 + .../org/apache/camel/main/components.properties | 1 + .../camel-component-known-dependencies.properties | 1 + parent/pom.xml | 6 ++ test-infra/camel-test-infra-smb/pom.xml | 55 ++++++++++ .../src/main/resources/META-INF/MANIFEST.MF | 0 .../camel/test/infra/smb/common/SmbProperties.java | 26 +++++ .../test/infra/smb/services/SmbContainer.java | 56 ++++++++++ .../smb/services/SmbLocalContainerService.java | 67 ++++++++++++ .../test/infra/smb/services/SmbRemoteService.java | 57 ++++++++++ .../camel/test/infra/smb/services/SmbService.java | 62 +++++++++++ .../test/infra/smb/services/SmbServiceFactory.java | 31 ++++++ .../camel/test/infra/smb/services/Dockerfile | 26 +++++ .../apache/camel/test/infra/smb/services/smb.conf | 59 +++++++++++ .../apache/camel/test/infra/smb/services/start.sh | 39 +++++++ test-infra/pom.xml | 1 + 40 files changed, 1583 insertions(+) diff --git a/bom/camel-bom/pom.xml b/bom/camel-bom/pom.xml index 14b5340c502..e65e00e3922 100644 --- a/bom/camel-bom/pom.xml +++ b/bom/camel-bom/pom.xml @@ -1722,6 +1722,11 @@ <artifactId>camel-slack</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-smb</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-smpp</artifactId> diff --git a/catalog/camel-allcomponents/pom.xml b/catalog/camel-allcomponents/pom.xml index e6e11882e51..649c378f157 100644 --- a/catalog/camel-allcomponents/pom.xml +++ b/catalog/camel-allcomponents/pom.xml @@ -1517,6 +1517,11 @@ <artifactId>camel-slack</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-smb</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-smpp</artifactId> diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties index 6a2c29e1e7b..c7a7518b6a5 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components.properties @@ -271,6 +271,7 @@ sftp sjms sjms2 slack +smb smpp smpps smtp diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smb.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smb.json new file mode 100644 index 00000000000..82a5f452475 --- /dev/null +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/smb.json @@ -0,0 +1,45 @@ +{ + "component": { + "kind": "component", + "name": "smb", + "title": "SMB", + "description": "SMB component which consumes natively from file shares using the Server Message Block (SMB, also known as Common Internet File System - CIFS) protocol", + "deprecated": false, + "firstVersion": "4.2.0-SNAPSHOT", + "label": "file", + "javaType": "org.apache.camel.component.smb.SmbComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-smb", + "version": "4.2.0-SNAPSHOT", + "scheme": "smb", + "extendsScheme": "", + "syntax": "smb:hostname:port", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the like [...] + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] + }, + "properties": { + "hostname": { "index": 0, "kind": "path", "displayName": "Hostname", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The share name or IP address" }, + "port": { "index": 1, "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 445, "description": "The share port" }, + "shareName": { "index": 2, "kind": "path", "displayName": "Share Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The share path" }, + "domain": { "index": 3, "kind": "parameter", "displayName": "Domain", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The user domain" }, + "password": { "index": 4, "kind": "parameter", "displayName": "Password", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The password to access the share" }, + "path": { "index": 5, "kind": "parameter", "displayName": "Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The path, within the share, to consume the files from" }, + "searchPattern": { "index": 6, "kind": "parameter", "displayName": "Search Pattern", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "*.txt", "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The search pattern used to list the files" }, + "smbIoBean": { "index": 7, "kind": "parameter", "displayName": "Smb Io Bean", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.smb.SmbIOBean", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "An optional SMB I\/O bean to use to setup the file access attributes when reading\/writing a file" }, + "username": { "index": 8, "kind": "parameter", "displayName": "Username", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The username required to access the share" }, + "idempotentRepository": { "index": 9, "kind": "parameter", "displayName": "Idempotent Repository", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.spi.IdempotentRepository", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "A pluggable repository org.apache.camel.spi.IdempotentRepository wh [...] + "bridgeErrorHandler": { "index": 10, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming [...] + "exceptionHandler": { "index": 11, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By de [...] + "exchangePattern": { "index": 12, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + } +} diff --git a/components/camel-smb/pom.xml b/components/camel-smb/pom.xml new file mode 100644 index 00000000000..2932045d297 --- /dev/null +++ b/components/camel-smb/pom.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + + 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. + +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.camel</groupId> + <artifactId>components</artifactId> + <version>4.2.0-SNAPSHOT</version> + </parent> + + <artifactId>camel-smb</artifactId> + <packaging>jar</packaging> + + <name>Camel :: SMB</name> + <description>Server Message Block (SMB) file shares</description> + + <dependencies> + + <!-- camel --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-support</artifactId> + </dependency> + + <!-- CIFS --> + <dependency> + <groupId>com.hierynomus</groupId> + <artifactId>smbj</artifactId> + <version>${smbj-version}</version> + </dependency> + + <!-- logging --> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-slf4j2-impl</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.logging.log4j</groupId> + <artifactId>log4j-core</artifactId> + <scope>test</scope> + </dependency> + + <!-- testing --> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-junit5</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-infra-smb</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + </dependency> + </dependencies> + +</project> diff --git a/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbComponentConfigurer.java b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbComponentConfigurer.java new file mode 100644 index 00000000000..503eb294177 --- /dev/null +++ b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbComponentConfigurer.java @@ -0,0 +1,61 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.smb; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@SuppressWarnings("unchecked") +public class SmbComponentConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + SmbComponent target = (SmbComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true; + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + default: return false; + } + } + + @Override + public Class<?> getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return boolean.class; + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + SmbComponent target = (SmbComponent) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "autowiredenabled": + case "autowiredEnabled": return target.isAutowiredEnabled(); + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + default: return null; + } + } +} + diff --git a/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointConfigurer.java b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointConfigurer.java new file mode 100644 index 00000000000..dcddda2fe2d --- /dev/null +++ b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointConfigurer.java @@ -0,0 +1,97 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.smb; + +import java.util.Map; + +import org.apache.camel.CamelContext; +import org.apache.camel.spi.ExtendedPropertyConfigurerGetter; +import org.apache.camel.spi.PropertyConfigurerGetter; +import org.apache.camel.spi.ConfigurerStrategy; +import org.apache.camel.spi.GeneratedPropertyConfigurer; +import org.apache.camel.util.CaseInsensitiveMap; +import org.apache.camel.support.component.PropertyConfigurerSupport; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +@SuppressWarnings("unchecked") +public class SmbEndpointConfigurer extends PropertyConfigurerSupport implements GeneratedPropertyConfigurer, PropertyConfigurerGetter { + + @Override + public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) { + SmbEndpoint target = (SmbEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "bridgeerrorhandler": + case "bridgeErrorHandler": target.setBridgeErrorHandler(property(camelContext, boolean.class, value)); return true; + case "domain": target.getConfiguration().setDomain(property(camelContext, java.lang.String.class, value)); return true; + case "exceptionhandler": + case "exceptionHandler": target.setExceptionHandler(property(camelContext, org.apache.camel.spi.ExceptionHandler.class, value)); return true; + case "exchangepattern": + case "exchangePattern": target.setExchangePattern(property(camelContext, org.apache.camel.ExchangePattern.class, value)); return true; + case "idempotentrepository": + case "idempotentRepository": target.getConfiguration().setIdempotentRepository(property(camelContext, org.apache.camel.spi.IdempotentRepository.class, value)); return true; + case "lazystartproducer": + case "lazyStartProducer": target.setLazyStartProducer(property(camelContext, boolean.class, value)); return true; + case "password": target.getConfiguration().setPassword(property(camelContext, java.lang.String.class, value)); return true; + case "path": target.getConfiguration().setPath(property(camelContext, java.lang.String.class, value)); return true; + case "searchpattern": + case "searchPattern": target.getConfiguration().setSearchPattern(property(camelContext, java.lang.String.class, value)); return true; + case "smbiobean": + case "smbIoBean": target.getConfiguration().setSmbIoBean(property(camelContext, org.apache.camel.component.smb.SmbIOBean.class, value)); return true; + case "username": target.getConfiguration().setUsername(property(camelContext, java.lang.String.class, value)); return true; + default: return false; + } + } + + @Override + public Class<?> getOptionType(String name, boolean ignoreCase) { + switch (ignoreCase ? name.toLowerCase() : name) { + case "bridgeerrorhandler": + case "bridgeErrorHandler": return boolean.class; + case "domain": return java.lang.String.class; + case "exceptionhandler": + case "exceptionHandler": return org.apache.camel.spi.ExceptionHandler.class; + case "exchangepattern": + case "exchangePattern": return org.apache.camel.ExchangePattern.class; + case "idempotentrepository": + case "idempotentRepository": return org.apache.camel.spi.IdempotentRepository.class; + case "lazystartproducer": + case "lazyStartProducer": return boolean.class; + case "password": return java.lang.String.class; + case "path": return java.lang.String.class; + case "searchpattern": + case "searchPattern": return java.lang.String.class; + case "smbiobean": + case "smbIoBean": return org.apache.camel.component.smb.SmbIOBean.class; + case "username": return java.lang.String.class; + default: return null; + } + } + + @Override + public Object getOptionValue(Object obj, String name, boolean ignoreCase) { + SmbEndpoint target = (SmbEndpoint) obj; + switch (ignoreCase ? name.toLowerCase() : name) { + case "bridgeerrorhandler": + case "bridgeErrorHandler": return target.isBridgeErrorHandler(); + case "domain": return target.getConfiguration().getDomain(); + case "exceptionhandler": + case "exceptionHandler": return target.getExceptionHandler(); + case "exchangepattern": + case "exchangePattern": return target.getExchangePattern(); + case "idempotentrepository": + case "idempotentRepository": return target.getConfiguration().getIdempotentRepository(); + case "lazystartproducer": + case "lazyStartProducer": return target.isLazyStartProducer(); + case "password": return target.getConfiguration().getPassword(); + case "path": return target.getConfiguration().getPath(); + case "searchpattern": + case "searchPattern": return target.getConfiguration().getSearchPattern(); + case "smbiobean": + case "smbIoBean": return target.getConfiguration().getSmbIoBean(); + case "username": return target.getConfiguration().getUsername(); + default: return null; + } + } +} + diff --git a/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointUriFactory.java b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointUriFactory.java new file mode 100644 index 00000000000..57dbf693919 --- /dev/null +++ b/components/camel-smb/src/generated/java/org/apache/camel/component/smb/SmbEndpointUriFactory.java @@ -0,0 +1,83 @@ +/* Generated by camel build tools - do NOT edit this file! */ +package org.apache.camel.component.smb; + +import java.net.URISyntaxException; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.camel.spi.EndpointUriFactory; + +/** + * Generated by camel build tools - do NOT edit this file! + */ +public class SmbEndpointUriFactory extends org.apache.camel.support.component.EndpointUriFactorySupport implements EndpointUriFactory { + + private static final String BASE = ":hostname:port"; + + private static final Set<String> PROPERTY_NAMES; + private static final Set<String> SECRET_PROPERTY_NAMES; + private static final Set<String> MULTI_VALUE_PREFIXES; + static { + Set<String> props = new HashSet<>(14); + props.add("bridgeErrorHandler"); + props.add("domain"); + props.add("exceptionHandler"); + props.add("exchangePattern"); + props.add("hostname"); + props.add("idempotentRepository"); + props.add("lazyStartProducer"); + props.add("password"); + props.add("path"); + props.add("port"); + props.add("searchPattern"); + props.add("shareName"); + props.add("smbIoBean"); + props.add("username"); + PROPERTY_NAMES = Collections.unmodifiableSet(props); + SECRET_PROPERTY_NAMES = Collections.emptySet(); + MULTI_VALUE_PREFIXES = Collections.emptySet(); + } + + @Override + public boolean isEnabled(String scheme) { + return "smb".equals(scheme); + } + + @Override + public String buildUri(String scheme, Map<String, Object> properties, boolean encode) throws URISyntaxException { + String syntax = scheme + BASE; + String uri = syntax; + + Map<String, Object> copy = new HashMap<>(properties); + + uri = buildPathParameter(syntax, uri, "hostname", null, true, copy); + uri = buildPathParameter(syntax, uri, "port", 445, false, copy); + uri = buildPathParameter(syntax, uri, "shareName", null, false, copy); + uri = buildQueryParameters(uri, copy, encode); + return uri; + } + + @Override + public Set<String> propertyNames() { + return PROPERTY_NAMES; + } + + @Override + public Set<String> secretPropertyNames() { + return SECRET_PROPERTY_NAMES; + } + + @Override + public Set<String> multiValuePrefixes() { + return MULTI_VALUE_PREFIXES; + } + + @Override + public boolean isLenientProperties() { + return false; + } +} + diff --git a/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component.properties b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component.properties new file mode 100644 index 00000000000..1f59881f4a3 --- /dev/null +++ b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component.properties @@ -0,0 +1,7 @@ +# Generated by camel build tools - do NOT edit this file! +components=smb +groupId=org.apache.camel +artifactId=camel-smb +version=4.2.0-SNAPSHOT +projectName=Camel :: SMB +projectDescription=Server Message Block (SMB) file shares diff --git a/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component/smb b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component/smb new file mode 100644 index 00000000000..ba665193f3d --- /dev/null +++ b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/component/smb @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.smb.SmbComponent diff --git a/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-component b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-component new file mode 100644 index 00000000000..c520762dd29 --- /dev/null +++ b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-component @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.smb.SmbComponentConfigurer diff --git a/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-endpoint b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-endpoint new file mode 100644 index 00000000000..bb1271301bc --- /dev/null +++ b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/configurer/smb-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.smb.SmbEndpointConfigurer diff --git a/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/urifactory/smb-endpoint b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/urifactory/smb-endpoint new file mode 100644 index 00000000000..d4661df9d67 --- /dev/null +++ b/components/camel-smb/src/generated/resources/META-INF/services/org/apache/camel/urifactory/smb-endpoint @@ -0,0 +1,2 @@ +# Generated by camel build tools - do NOT edit this file! +class=org.apache.camel.component.smb.SmbEndpointUriFactory diff --git a/components/camel-smb/src/generated/resources/org/apache/camel/component/smb/smb.json b/components/camel-smb/src/generated/resources/org/apache/camel/component/smb/smb.json new file mode 100644 index 00000000000..82a5f452475 --- /dev/null +++ b/components/camel-smb/src/generated/resources/org/apache/camel/component/smb/smb.json @@ -0,0 +1,45 @@ +{ + "component": { + "kind": "component", + "name": "smb", + "title": "SMB", + "description": "SMB component which consumes natively from file shares using the Server Message Block (SMB, also known as Common Internet File System - CIFS) protocol", + "deprecated": false, + "firstVersion": "4.2.0-SNAPSHOT", + "label": "file", + "javaType": "org.apache.camel.component.smb.SmbComponent", + "supportLevel": "Preview", + "groupId": "org.apache.camel", + "artifactId": "camel-smb", + "version": "4.2.0-SNAPSHOT", + "scheme": "smb", + "extendsScheme": "", + "syntax": "smb:hostname:port", + "async": false, + "api": false, + "consumerOnly": false, + "producerOnly": false, + "lenientProperties": false + }, + "componentProperties": { + "bridgeErrorHandler": { "index": 0, "kind": "property", "displayName": "Bridge Error Handler", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming messages, or the like [...] + "lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...] + "autowiredEnabled": { "index": 2, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...] + }, + "properties": { + "hostname": { "index": 0, "kind": "path", "displayName": "Hostname", "group": "common", "label": "common", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The share name or IP address" }, + "port": { "index": 1, "kind": "path", "displayName": "Port", "group": "common", "label": "", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "autowired": false, "secret": false, "defaultValue": 445, "description": "The share port" }, + "shareName": { "index": 2, "kind": "path", "displayName": "Share Name", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The share path" }, + "domain": { "index": 3, "kind": "parameter", "displayName": "Domain", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The user domain" }, + "password": { "index": 4, "kind": "parameter", "displayName": "Password", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The password to access the share" }, + "path": { "index": 5, "kind": "parameter", "displayName": "Path", "group": "common", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The path, within the share, to consume the files from" }, + "searchPattern": { "index": 6, "kind": "parameter", "displayName": "Search Pattern", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "defaultValue": "*.txt", "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The search pattern used to list the files" }, + "smbIoBean": { "index": 7, "kind": "parameter", "displayName": "Smb Io Bean", "group": "common", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.smb.SmbIOBean", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "An optional SMB I\/O bean to use to setup the file access attributes when reading\/writing a file" }, + "username": { "index": 8, "kind": "parameter", "displayName": "Username", "group": "common", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "The username required to access the share" }, + "idempotentRepository": { "index": 9, "kind": "parameter", "displayName": "Idempotent Repository", "group": "consumer", "label": "consumer", "required": false, "type": "object", "javaType": "org.apache.camel.spi.IdempotentRepository", "deprecated": false, "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.smb.SmbConfiguration", "configurationField": "configuration", "description": "A pluggable repository org.apache.camel.spi.IdempotentRepository wh [...] + "bridgeErrorHandler": { "index": 10, "kind": "parameter", "displayName": "Bridge Error Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Allows for bridging the consumer to the Camel routing Error Handler, which mean any exceptions (if possible) occurred while the Camel consumer is trying to pickup incoming [...] + "exceptionHandler": { "index": 11, "kind": "parameter", "displayName": "Exception Handler", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", "deprecated": false, "autowired": false, "secret": false, "description": "To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this option is not in use. By de [...] + "exchangePattern": { "index": 12, "kind": "parameter", "displayName": "Exchange Pattern", "group": "consumer (advanced)", "label": "consumer,advanced", "required": false, "type": "object", "javaType": "org.apache.camel.ExchangePattern", "enum": [ "InOnly", "InOut" ], "deprecated": false, "autowired": false, "secret": false, "description": "Sets the exchange pattern when the consumer creates an exchange." }, + "lazyStartProducer": { "index": 13, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produ [...] + } +} diff --git a/components/camel-smb/src/main/docs/smb-component.adoc b/components/camel-smb/src/main/docs/smb-component.adoc new file mode 100644 index 00000000000..bd0a08a801e --- /dev/null +++ b/components/camel-smb/src/main/docs/smb-component.adoc @@ -0,0 +1,57 @@ += SMB Component +:doctitle: SMB +:shortname: smb +:artifactid: camel-smb +:description: SMB component which consumes natively from file shares using the Server Message Block (SMB, also known as Common Internet File System - CIFS) protocol +:since: 4.2.0-SNAPSHOT +:supportlevel: Preview +:tabs-sync-option: +:component-header: Both producer and consumer are supported + +*Since Camel {since}* + +*{component-header}* + +The Server Message Block (SMB) component provides a way to connect natively to SMB file shares, such as those provided by Microsoft Windows or https://www.samba.org/[Samba]. + + +[source,xml] +---- +<dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-smb</artifactId> + <version>x.x.x</version> + <!-- use the same version as your Camel core version --> +</dependency> +---- + +== URI format + +---- +smb:address[:port]/shareName[?options] +---- + +== Usage + +For instance, polling all the files from a SMB file share and reading their contents would look like this: + +[source,java] +---- +private void process(Exchange exchange) throws IOException { + final File file = exchange.getMessage().getBody(File.class); + try (InputStream inputStream = file.getInputStream()) { + LOG.debug("Read exchange: {}, with contents: {}", file.getFileInformation(), new String(inputStream.readAllBytes())); + } +} + +public void configure() { + fromF("smb:%s/%s?username=%s&password=%s&path=/", service.address(), service.shareName(), service.userName(), service.password()) + .process(this::process) + .to("mock:result"); +} +---- + +[NOTE] +==== +Beware that the File object provided is not a java.io.File instance, but, instead a com.hierynomus.smbj.share.File instance. +==== diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbComponent.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbComponent.java new file mode 100644 index 00000000000..411ae2b208f --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbComponent.java @@ -0,0 +1,68 @@ +/* + * 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.camel.component.smb; + +import java.util.Map; + +import org.apache.camel.Endpoint; +import org.apache.camel.spi.annotations.Component; +import org.apache.camel.support.DefaultComponent; +import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.StringHelper; + +@Component("smb") +public class SmbComponent extends DefaultComponent { + + protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception { + if (ObjectHelper.isEmpty(remaining)) { + throw new IllegalArgumentException("Host IP or address must be configured on endpoint using syntax smb:host:port"); + } + + final SmbEndpoint endpoint = new SmbEndpoint(uri, this); + + final String hostPart = StringHelper.before(remaining, "/"); + if (hostPart != null && hostPart.contains(":")) { + parseHost(hostPart, endpoint); + } else { + endpoint.setHostname(hostPart); + } + + String path = StringHelper.after(remaining, "/"); + + setProperties(endpoint, parameters); + endpoint.setShareName(path); + + return endpoint; + } + + private static void parseHost(String hostPart, SmbEndpoint endpoint) { + // Host part is in the format hostname:port or ip:port + String host = StringHelper.before(hostPart, ":"); + if (ObjectHelper.isEmpty(host)) { + throw new IllegalArgumentException("Invalid host or address: " + hostPart); + } + + endpoint.setHostname(host); + + String port = StringHelper.after(hostPart, ":"); + if (ObjectHelper.isEmpty(port)) { + throw new IllegalArgumentException("Invalid port given on host: " + hostPart); + } + + endpoint.setPort(Integer.parseInt(port)); + } +} diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConfiguration.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConfiguration.java new file mode 100644 index 00000000000..30f2acdb5a1 --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConfiguration.java @@ -0,0 +1,110 @@ +/* + * 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.camel.component.smb; + +import org.apache.camel.spi.IdempotentRepository; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriParams; +import org.apache.camel.support.processor.idempotent.MemoryIdempotentRepository; + +@UriParams +public class SmbConfiguration implements Cloneable { + + protected static final int DEFAULT_IDEMPOTENT_CACHE_SIZE = 1000; + + @UriParam(description = "The username required to access the share") + private String username; + + @UriParam(description = "The password to access the share") + private String password; + + @UriParam(description = "The user domain") + private String domain; + + @Metadata(required = true) + @UriParam(description = "The path, within the share, to consume the files from") + private String path; + + @UriParam(defaultValue = "*.txt", description = "The search pattern used to list the files") + private String searchPattern; + + @UriParam(description = "An optional SMB I/O bean to use to setup the file access attributes when reading/writing a file") + private SmbIOBean smbIoBean = new SmbReadBean(); + + @UriParam(label = "consumer", description = "A pluggable repository org.apache.camel.spi.IdempotentRepository " + + "which by default use MemoryIdempotentRepository if none is specified and idempotent is true.") + protected IdempotentRepository idempotentRepository + = MemoryIdempotentRepository.memoryIdempotentRepository(DEFAULT_IDEMPOTENT_CACHE_SIZE); + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public SmbIOBean getSmbIoBean() { + return smbIoBean; + } + + public void setSmbIoBean(SmbIOBean smbIoBean) { + this.smbIoBean = smbIoBean; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getSearchPattern() { + return searchPattern; + } + + public void setSearchPattern(String searchPattern) { + this.searchPattern = searchPattern; + } + + public IdempotentRepository getIdempotentRepository() { + return idempotentRepository; + } + + public void setIdempotentRepository(IdempotentRepository idempotentRepository) { + this.idempotentRepository = idempotentRepository; + } +} diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConsumer.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConsumer.java new file mode 100644 index 00000000000..0bc118fb257 --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbConsumer.java @@ -0,0 +1,86 @@ +/* + * 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.camel.component.smb; + +import com.hierynomus.msfscc.fileinformation.FileIdBothDirectoryInformation; +import com.hierynomus.smbj.SMBClient; +import com.hierynomus.smbj.auth.AuthenticationContext; +import com.hierynomus.smbj.connection.Connection; +import com.hierynomus.smbj.session.Session; +import com.hierynomus.smbj.share.DiskShare; +import com.hierynomus.smbj.share.File; +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.spi.IdempotentRepository; +import org.apache.camel.support.ScheduledPollConsumer; + +public class SmbConsumer extends ScheduledPollConsumer { + private final SmbEndpoint endpoint; + private final SmbConfiguration configuration; + + private final SMBClient smbClient = new SMBClient(); + + public SmbConsumer(SmbEndpoint endpoint, Processor processor) { + super(endpoint, processor); + this.endpoint = endpoint; + this.configuration = endpoint.getConfiguration(); + } + + @Override + protected int poll() throws Exception { + int polledCount = 0; + + // start a single threaded pool to monitor events + try (Connection connection = smbClient.connect(endpoint.getHostname(), endpoint.getPort())) { + AuthenticationContext ac = new AuthenticationContext( + configuration.getUsername(), configuration.getPassword().toCharArray(), + configuration.getDomain()); + Session session = connection.authenticate(ac); + + // Connect to Share + try (DiskShare share = (DiskShare) session.connectShare(endpoint.getShareName())) { + SmbIOBean smbIOBean = configuration.getSmbIoBean(); + + IdempotentRepository repository = configuration.getIdempotentRepository(); + + for (FileIdBothDirectoryInformation f : share.list(configuration.getPath(), configuration.getSearchPattern())) { + if (f.getFileName().equals(".") || f.getFileName().equals("..")) { + continue; + } + + if (!repository.contains(f.getFileName())) { + polledCount++; + final Exchange exchange = createExchange(false); + + final File file = share.openFile(f.getFileName(), + smbIOBean.accessMask(), + smbIOBean.attributes(), + smbIOBean.shareAccesses(), + smbIOBean.createDisposition(), + smbIOBean.createOptions()); + + repository.add(f.getFileName()); + exchange.getMessage().setBody(file); + getProcessor().process(exchange); + } + } + } + } + + return polledCount; + } +} diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbEndpoint.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbEndpoint.java new file mode 100644 index 00000000000..ff51df443be --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbEndpoint.java @@ -0,0 +1,115 @@ +/* + * 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.camel.component.smb; + +import org.apache.camel.Category; +import org.apache.camel.Consumer; +import org.apache.camel.Processor; +import org.apache.camel.Producer; +import org.apache.camel.spi.Metadata; +import org.apache.camel.spi.UriEndpoint; +import org.apache.camel.spi.UriParam; +import org.apache.camel.spi.UriPath; +import org.apache.camel.support.DefaultEndpoint; + +/** + * SMB component which consumes natively from file shares using the Server Message Block (SMB, also known as Common + * Internet File System - CIFS) protocol + */ +@UriEndpoint(firstVersion = "4.2.0-SNAPSHOT", scheme = "smb", title = "SMB", syntax = "smb:hostname:port", + category = { Category.FILE }) +public class SmbEndpoint extends DefaultEndpoint { + @UriParam + private SmbConfiguration configuration = new SmbConfiguration(); + + @UriPath(label = "common") + @Metadata(required = true) + private String hostname; + + @UriPath(defaultValue = "445") + private int port; + + @UriPath + private String shareName; + + public SmbEndpoint() { + } + + public SmbEndpoint(String uri, SmbComponent component) { + super(uri, component); + } + + @Override + public Producer createProducer() { + throw new UnsupportedOperationException("SMB producer is not supported."); + } + + @Override + public Consumer createConsumer(Processor processor) throws Exception { + Consumer consumer = new SmbConsumer(this, processor); + configureConsumer(consumer); + return consumer; + } + + public SmbConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration(SmbConfiguration configuration) { + this.configuration = configuration; + } + + public String getHostname() { + return hostname; + } + + /** + * The share name or IP address + * + * @param hostname + */ + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public int getPort() { + return port; + } + + /** + * The share port + * + * @param port + */ + public void setPort(int port) { + this.port = port; + } + + public String getShareName() { + return shareName; + } + + /** + * The share path + * + * @param shareName + */ + public void setShareName(String shareName) { + this.shareName = shareName; + } + +} diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbIOBean.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbIOBean.java new file mode 100644 index 00000000000..1205ef8bbd2 --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbIOBean.java @@ -0,0 +1,65 @@ +/* + * 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.camel.component.smb; + +import java.util.Set; + +import com.hierynomus.msdtyp.AccessMask; +import com.hierynomus.msfscc.FileAttributes; +import com.hierynomus.mssmb2.SMB2CreateDisposition; +import com.hierynomus.mssmb2.SMB2CreateOptions; +import com.hierynomus.mssmb2.SMB2ShareAccess; + +public interface SmbIOBean { + + /** + * The access mask to use when opening a file + * + * @return + */ + Set<AccessMask> accessMask(); + + /** + * The attributes to request when opening a file + * + * @return + */ + Set<FileAttributes> attributes(); + + /** + * The share access to request when opening a file + * + * @return + */ + Set<SMB2ShareAccess> shareAccesses(); + + /** + * The create disposition to use when opening a file + * + * @return + */ + SMB2CreateDisposition createDisposition(); + + /** + * The file create options (if applicable) + * + * @return + */ + Set<SMB2CreateOptions> createOptions(); + +} diff --git a/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbReadBean.java b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbReadBean.java new file mode 100644 index 00000000000..9f551b9f4d1 --- /dev/null +++ b/components/camel-smb/src/main/java/org/apache/camel/component/smb/SmbReadBean.java @@ -0,0 +1,55 @@ +/* + * 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.camel.component.smb; + +import java.util.EnumSet; +import java.util.Set; + +import com.hierynomus.msdtyp.AccessMask; +import com.hierynomus.msfscc.FileAttributes; +import com.hierynomus.mssmb2.SMB2CreateDisposition; +import com.hierynomus.mssmb2.SMB2CreateOptions; +import com.hierynomus.mssmb2.SMB2ShareAccess; + +public class SmbReadBean implements SmbIOBean { + + @Override + public Set<AccessMask> accessMask() { + return EnumSet.of(AccessMask.GENERIC_READ); + } + + @Override + public Set<FileAttributes> attributes() { + return EnumSet.of(FileAttributes.FILE_ATTRIBUTE_NORMAL); + } + + @Override + public Set<SMB2ShareAccess> shareAccesses() { + return EnumSet.of(SMB2ShareAccess.FILE_SHARE_READ); + } + + @Override + public SMB2CreateDisposition createDisposition() { + return SMB2CreateDisposition.FILE_OPEN; + } + + @Override + public Set<SMB2CreateOptions> createOptions() { + return EnumSet.noneOf(SMB2CreateOptions.class); + } +} diff --git a/components/camel-smb/src/main/resources/META-INF/services/org/apache/camel/component/smb b/components/camel-smb/src/main/resources/META-INF/services/org/apache/camel/component/smb new file mode 100644 index 00000000000..559daeb689d --- /dev/null +++ b/components/camel-smb/src/main/resources/META-INF/services/org/apache/camel/component/smb @@ -0,0 +1 @@ +class=org.apache.camel.component.smb.SmbComponent diff --git a/components/camel-smb/src/test/java/org/apache/camel/component/smb/SmbComponentIT.java b/components/camel-smb/src/test/java/org/apache/camel/component/smb/SmbComponentIT.java new file mode 100644 index 00000000000..e90aceca8a5 --- /dev/null +++ b/components/camel-smb/src/test/java/org/apache/camel/component/smb/SmbComponentIT.java @@ -0,0 +1,68 @@ +/* + * 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.camel.component.smb; + +import java.io.IOException; +import java.io.InputStream; + +import com.hierynomus.smbj.share.File; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.infra.smb.services.SmbService; +import org.apache.camel.test.infra.smb.services.SmbServiceFactory; +import org.apache.camel.test.junit5.CamelTestSupport; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SmbComponentIT extends CamelTestSupport { + private static final Logger LOG = LoggerFactory.getLogger(SmbComponentIT.class); + + @RegisterExtension + public static SmbService service = SmbServiceFactory.createService(); + + @Test + public void testSmbRead() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(100); + + mock.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + private void process(Exchange exchange) throws IOException { + final File file = exchange.getMessage().getBody(File.class); + try (InputStream inputStream = file.getInputStream()) { + + LOG.debug("Read exchange: {}, with contents: {}", file.getPath(), + new String(inputStream.readAllBytes())); + } + } + + public void configure() { + fromF("smb:%s/%s?username=%s&password=%s&path=/", service.address(), service.shareName(), + service.userName(), service.password()) + .process(this::process) + .to("mock:result"); + } + }; + } +} diff --git a/components/camel-smb/src/test/resources/log4j2.properties b/components/camel-smb/src/test/resources/log4j2.properties new file mode 100644 index 00000000000..38b39e5b760 --- /dev/null +++ b/components/camel-smb/src/test/resources/log4j2.properties @@ -0,0 +1,35 @@ +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +appender.out.type = File +appender.out.name = out +appender.out.fileName = target/camel-smb-test.log +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +appender.stdout.type = Console +appender.stdout.name = stdout +appender.stdout.layout.type = PatternLayout +appender.stdout.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n + +rootLogger.level = WARN +rootLogger.appenderRef.out.ref = out + +logger.camel.name=org.apache.camel +logger.camel.level=INFO + +logger.camel-smb.name=org.apache.camel.component.smb +logger.camel-smb.level=DEBUG \ No newline at end of file diff --git a/components/pom.xml b/components/pom.xml index bf4142c2490..cc445ae89ae 100644 --- a/components/pom.xml +++ b/components/pom.xml @@ -265,6 +265,7 @@ <module>camel-sjms2</module> <module>camel-sjms</module> <module>camel-slack</module> + <module>camel-smb</module> <module>camel-smpp</module> <module>camel-snakeyaml</module> <module>camel-snmp</module> diff --git a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties index 6a2c29e1e7b..c7a7518b6a5 100644 --- a/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties +++ b/core/camel-main/src/generated/resources/org/apache/camel/main/components.properties @@ -271,6 +271,7 @@ sftp sjms sjms2 slack +smb smpp smpps smtp diff --git a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties index 5bae8cbb47f..c2911fbb9b9 100644 --- a/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties +++ b/dsl/camel-kamelet-main/src/generated/resources/camel-component-known-dependencies.properties @@ -281,6 +281,7 @@ org.apache.camel.component.servlet.ServletComponent=camel:servlet org.apache.camel.component.sjms.SjmsComponent=camel:sjms org.apache.camel.component.sjms2.Sjms2Component=camel:sjms2 org.apache.camel.component.slack.SlackComponent=camel:slack +org.apache.camel.component.smb.SmbComponent=camel:smb org.apache.camel.component.smpp.SmppComponent=camel:smpp org.apache.camel.component.snmp.SnmpComponent=camel:snmp org.apache.camel.component.splunk.SplunkComponent=camel:splunk diff --git a/parent/pom.xml b/parent/pom.xml index a2d3cef431e..2b61d6e58c6 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -416,6 +416,7 @@ <smallrye-config-version>3.3.2</smallrye-config-version> <smallrye-health-version>4.0.2</smallrye-health-version> <smallrye-fault-tolerance-version>6.2.6</smallrye-fault-tolerance-version> + <smbj-version>0.12.0</smbj-version> <snakeyaml-version>2.0</snakeyaml-version> <snakeyaml-engine-version>2.7</snakeyaml-engine-version> <snmp4j-version>3.7.7</snmp4j-version> @@ -2112,6 +2113,11 @@ <artifactId>camel-slack</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-smb</artifactId> + <version>${project.version}</version> + </dependency> <dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-smpp</artifactId> diff --git a/test-infra/camel-test-infra-smb/pom.xml b/test-infra/camel-test-infra-smb/pom.xml new file mode 100644 index 00000000000..997ba25a8b1 --- /dev/null +++ b/test-infra/camel-test-infra-smb/pom.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ 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. + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>camel-test-infra-parent</artifactId> + <groupId>org.apache.camel</groupId> + <relativePath>../camel-test-infra-parent/pom.xml</relativePath> + <version>4.2.0-SNAPSHOT</version> + </parent> + + <artifactId>camel-test-infra-smb</artifactId> + <name>Camel :: Test Infra :: Server Message Block</name> + <description>Server Message Block test infrastructure for Camel</description> + + <dependencies> + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-infra-common</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + </dependency> + + <dependency> + <groupId>org.testcontainers</groupId> + <artifactId>testcontainers</artifactId> + <version>${testcontainers-version}</version> + </dependency> + + <dependency> + <groupId>org.apache.camel</groupId> + <artifactId>camel-test-junit5</artifactId> + </dependency> + </dependencies> + + +</project> \ No newline at end of file diff --git a/test-infra/camel-test-infra-smb/src/main/resources/META-INF/MANIFEST.MF b/test-infra/camel-test-infra-smb/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/common/SmbProperties.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/common/SmbProperties.java new file mode 100644 index 00000000000..9863a2777db --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/common/SmbProperties.java @@ -0,0 +1,26 @@ +/* + * 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.camel.test.infra.smb.common; + +public class SmbProperties { + public static final String SERVICE_ADDRESS = "smb.service.address"; + public static final String SHARE_NAME = "smb.service.share"; + public static final String SMB_USERNAME = "smb.service.username"; + public static final String SMB_PASSWORD = "smb.service.password"; + +} diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbContainer.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbContainer.java new file mode 100644 index 00000000000..e8aaec79d56 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbContainer.java @@ -0,0 +1,56 @@ +/* + * 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.camel.test.infra.smb.services; + +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.containers.wait.strategy.Wait; +import org.testcontainers.images.builder.ImageFromDockerfile; + +public class SmbContainer extends GenericContainer<SmbContainer> { + + public static final int SMB_PORT_DEFAULT = 445; + public static final String DEFAULT_USER = "camel"; + public static final String DEFAULT_PASSWORD = "camelTester123"; + + public SmbContainer() { + super(new ImageFromDockerfile("localhost/samba:camel", false) + .withFileFromClasspath(".", + "org/apache/camel/test/infra/smb/services/")); + + super.withExposedPorts(SMB_PORT_DEFAULT) + .waitingFor(Wait.forListeningPort()); + } + + + public String getUser() { + return DEFAULT_USER; + } + + public String getPassword() { + return DEFAULT_PASSWORD; + } + + public String getShare() { + return "data-rw"; + } + + + public int getPort() { + return getMappedPort(SMB_PORT_DEFAULT); + } +} diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbLocalContainerService.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbLocalContainerService.java new file mode 100644 index 00000000000..8fde98768c5 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbLocalContainerService.java @@ -0,0 +1,67 @@ +/* + * 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.camel.test.infra.smb.services; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SmbLocalContainerService implements SmbService { + private static final Logger LOG = LoggerFactory.getLogger(SmbLocalContainerService.class); + private final SmbContainer container = new SmbContainer(); + + public SmbLocalContainerService() { + } + + @Override + public String address() { + return container.getHost() + ":" + container.getPort(); + } + + @Override + public String shareName() { + return container.getShare(); + } + + @Override + public String userName() { + return container.getUser(); + } + + @Override + public String password() { + return container.getPassword(); + } + + @Override + public void registerProperties() { + + } + + @Override + public void initialize() { + container.start(); + registerProperties(); + + LOG.info("SMB host running at address {}:", address()); + } + + @Override + public void shutdown() { + + } +} diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbRemoteService.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbRemoteService.java new file mode 100644 index 00000000000..62de562a9c3 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbRemoteService.java @@ -0,0 +1,57 @@ +/* + * 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.camel.test.infra.smb.services; + +import org.apache.camel.test.infra.smb.common.SmbProperties; + +public class SmbRemoteService implements SmbService { + @Override + public String address() { + return System.getProperty(SmbProperties.SERVICE_ADDRESS); + } + + @Override + public String shareName() { + return System.getProperty(SmbProperties.SHARE_NAME); + } + + @Override + public String userName() { + return System.getProperty(SmbProperties.SMB_USERNAME); + } + + @Override + public String password() { + return System.getProperty(SmbProperties.SMB_PASSWORD); + } + + @Override + public void registerProperties() { + + } + + @Override + public void initialize() { + + } + + @Override + public void shutdown() { + + } +} diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbService.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbService.java new file mode 100644 index 00000000000..526e56a5f66 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbService.java @@ -0,0 +1,62 @@ +/* + * 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.camel.test.infra.smb.services; + +import org.apache.camel.test.infra.common.services.TestService; +import org.junit.jupiter.api.extension.AfterTestExecutionCallback; +import org.junit.jupiter.api.extension.BeforeTestExecutionCallback; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public interface SmbService extends TestService, BeforeTestExecutionCallback, AfterTestExecutionCallback { + String address(); + String shareName(); + String userName(); + String password(); + + @Override + default void beforeAll(ExtensionContext extensionContext) { + try { + initialize(); + } catch (Exception e) { + Logger log = LoggerFactory.getLogger(SmbService.class); + + final Object o = extensionContext.getTestInstance().get(); + log.error("Failed to initialize service {} for test {} on ({})", this.getClass().getSimpleName(), + extensionContext.getDisplayName(), o.getClass().getName()); + + throw e; + } + } + + @Override + default void beforeTestExecution(ExtensionContext extensionContext) { + //no op + } + + @Override + default void afterAll(ExtensionContext extensionContext) { + shutdown(); + } + + @Override + default void afterTestExecution(ExtensionContext context) { + //no op + } +} diff --git a/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbServiceFactory.java b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbServiceFactory.java new file mode 100644 index 00000000000..48935c8c525 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/java/org/apache/camel/test/infra/smb/services/SmbServiceFactory.java @@ -0,0 +1,31 @@ +/* + * 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.camel.test.infra.smb.services; + +import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder; + +public class SmbServiceFactory { + + public static SmbService createService() { + SimpleTestServiceBuilder<SmbService> builder = new SimpleTestServiceBuilder<>("kafka"); + + return builder.addLocalMapping(SmbLocalContainerService::new) + .addRemoteMapping(SmbRemoteService::new) + .build(); + } +} diff --git a/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/Dockerfile b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/Dockerfile new file mode 100644 index 00000000000..5c7a8b5222e --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/Dockerfile @@ -0,0 +1,26 @@ +# +# 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. +# + +FROM fedora:38 as samba +LABEL maintainer="orpi...@apache.org" +ENV SAMBA_ROOT /opt/camel/samba +EXPOSE 139 445 +RUN dnf install -y samba && mkdir -p /data/rw /data/ro +ADD smb.conf /etc/samba/smb.conf +ADD start.sh /usr/local/bin +RUN chmod +x /usr/local/bin/start.sh +CMD /usr/local/bin/start.sh \ No newline at end of file diff --git a/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/smb.conf b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/smb.conf new file mode 100644 index 00000000000..74ef80abdda --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/smb.conf @@ -0,0 +1,59 @@ +# 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. + +[global] + workgroup = SAMBA + security = user + + passdb backend = tdbsam + + printing = cups + printcap name = cups + load printers = yes + cups options = raw + +[homes] + comment = Home Directories + valid users = %S, %D%w%S + browseable = No + read only = No + inherit acls = Yes + +[printers] + comment = All Printers + path = /var/tmp + printable = Yes + create mask = 0600 + browseable = No + +[print$] + comment = Printer Drivers + path = /var/lib/samba/drivers + write list = @printadmin root + force group = @printadmin + create mask = 0664 + directory mask = 0775 + +[data-rw] + comment = Read-write share for testing + path = /data/rw + read only = no + browsable = yes + +[data-ro] + comment = Read-only share for testing + path = /data/ro + read only = yes + browsable = yes diff --git a/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/start.sh b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/start.sh new file mode 100644 index 00000000000..2e1f950f656 --- /dev/null +++ b/test-infra/camel-test-infra-smb/src/test/resources/org/apache/camel/test/infra/smb/services/start.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# 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. +# + +echo "Creating read-writable files" +for file in $(seq 1 100) ; do + echo ${RANDOM} > /data/rw/${file}.txt ; +done + +echo "Creating read-only files" +for file in $(seq 1 100) ; do + echo ${RANDOM} > /data/ro/${file}.txt ; +done + +useradd camel +printf "camelTester123\ncamelTester123\n" | smbpasswd -s -a camel + +chown -Rv camel /data/rw + +nmbd -D +smbd -D -s /etc/samba/smb.conf + +while true ; do + sleep 10 +done \ No newline at end of file diff --git a/test-infra/pom.xml b/test-infra/pom.xml index e70a7cceb20..13af41583a2 100644 --- a/test-infra/pom.xml +++ b/test-infra/pom.xml @@ -76,5 +76,6 @@ <module>camel-test-infra-etcd3</module> <module>camel-test-infra-core</module> <module>camel-test-infra-opensearch</module> + <module>camel-test-infra-smb</module> </modules> </project>