This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-email.git

commit 7cff3880188ca96b37ada69cdf103ef9e8235e29
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sat Dec 16 11:50:12 2023 -0500

    Add DataSourcePathResolver
    
    Add PathDataSource
---
 src/changes/changes.xml                            |   2 +
 .../commons/mail/activation/PathDataSource.java    | 129 +++++++++++++++++++++
 .../mail/resolver/DataSourcePathResolver.java      | 102 ++++++++++++++++
 .../mail/resolver/DataSourcePathResolverTest.java  |  53 +++++++++
 4 files changed, 286 insertions(+)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index baaf786..a469379 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -50,6 +50,8 @@
       <action type="add" due-to="Gary Gregory" dev="ggregory">Add 
EmailConstants.SOCKET_TIMEOUT and deprecate SOCKET_TIMEOUT_MS.</action>
       <action type="add" due-to="Gary Gregory" dev="ggregory">Add 
Email.setSocketConnectionTimeout(Duration) and deprecate 
setSocketConnectionTimeout(int).</action>
       <action type="add" due-to="Gary Gregory" dev="ggregory">Add 
Email.setSocketTimeout(Duration) and deprecate setSocketTimeout(int).</action>
+      <action type="add" due-to="Gary Gregory" dev="ggregory">Add 
PathDataSource.</action>
+      <action type="add" due-to="Gary Gregory" dev="ggregory">Add 
DataSourcePathResolver.</action>
       <!-- UPDATE -->
       <action type="update" due-to="Dependabot" dev="sebb">Bump 
org.slf4j:slf4j-jdk14 from 1.7.7 to 2.0.9 #165.</action>
       <action type="update" due-to="Dependabot" dev="sebb">Bump mockito-core 
from 4.11.0 to 5.8.0 #187.</action>
diff --git 
a/src/main/java/org/apache/commons/mail/activation/PathDataSource.java 
b/src/main/java/org/apache/commons/mail/activation/PathDataSource.java
new file mode 100644
index 0000000..8c33a0d
--- /dev/null
+++ b/src/main/java/org/apache/commons/mail/activation/PathDataSource.java
@@ -0,0 +1,129 @@
+/*
+ * 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.commons.mail.activation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
+
+import javax.activation.DataSource;
+import javax.activation.FileTypeMap;
+
+/**
+ * Implements a simple DataSource object that encapsulates a Path. It provides 
data typing services via a FileTypeMap object.
+ *
+ * @see javax.activation.DataSource
+ * @see javax.activation.FileTypeMap
+ * @see javax.activation.MimetypesFileTypeMap
+ *
+ * @since 1.6.0
+ */
+public class PathDataSource implements DataSource {
+
+    private final Path path;
+    private final FileTypeMap typeMap;
+
+    /**
+     * Creates a new instance from a Path.
+     * <p>
+     * The file will not actually be opened until a method is called that 
requires the path to be opened.
+     * </p>
+     * <p>
+     * The type map defaults to {@link FileTypeMap#getDefaultFileTypeMap()}.
+     *
+     * @param path the path
+     */
+    public PathDataSource(final Path path) {
+        this(path, FileTypeMap.getDefaultFileTypeMap());
+    }
+
+    /**
+     * Creates a new instance from a Path.
+     * <p>
+     * The file will not actually be opened until a method is called that 
requires the path to be opened.
+     * </p>
+     *
+     * @param path    the path, non-null.
+     * @param typeMap the type map, non-null.
+     */
+    public PathDataSource(final Path path, final FileTypeMap typeMap) {
+        this.path = Objects.requireNonNull(path, "path");
+        this.typeMap = Objects.requireNonNull(typeMap, "typeMap");
+    }
+
+    /**
+     * Gets the MIME type of the data as a String. This method uses the 
currently installed FileTypeMap. If there is no FileTypeMap explicitly set, the
+     * FileDataSource will call the <code>getDefaultFileTypeMap</code> method 
on FileTypeMap to acquire a default FileTypeMap.
+     * <p>
+     * By default, the FileTypeMap used will be a MimetypesFileTypeMap.
+     * </p>
+     *
+     * @return the MIME Type
+     * @see javax.activation.FileTypeMap#getDefaultFileTypeMap
+     */
+    @Override
+    public String getContentType() {
+        return typeMap.getContentType(getName());
+    }
+
+    /**
+     * Gets an InputStream representing the the data and will throw an 
IOException if it can not do so. This method will return a new instance of 
InputStream
+     * with each invocation.
+     *
+     * @return an InputStream
+     */
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return Files.newInputStream(path);
+    }
+
+    /**
+     * Gets the <i>name</i> of this object. The FileDataSource will return the 
file name of the object.
+     *
+     * @return the name of the object.
+     * @see javax.activation.DataSource
+     */
+    @Override
+    public String getName() {
+        return path.getFileName().toString();
+    }
+
+    /**
+     * Gets an OutputStream representing the the data and will throw an 
IOException if it can not do so. This method will return a new instance of 
OutputStream
+     * with each invocation.
+     *
+     * @return an OutputStream
+     */
+    @Override
+    public OutputStream getOutputStream() throws IOException {
+        return Files.newOutputStream(path);
+    }
+
+    /**
+     * Gets the File object that corresponds to this FileDataSource.
+     *
+     * @return the File object for the file represented by this object.
+     */
+    public Path getPath() {
+        return path;
+    }
+
+}
diff --git 
a/src/main/java/org/apache/commons/mail/resolver/DataSourcePathResolver.java 
b/src/main/java/org/apache/commons/mail/resolver/DataSourcePathResolver.java
new file mode 100644
index 0000000..a17be23
--- /dev/null
+++ b/src/main/java/org/apache/commons/mail/resolver/DataSourcePathResolver.java
@@ -0,0 +1,102 @@
+/*
+ * 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.commons.mail.resolver;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import javax.activation.DataSource;
+
+import org.apache.commons.mail.activation.PathDataSource;
+
+/**
+ * Creates a {@code DataSource} based on a Path. The implementation also 
resolves file resources.
+ *
+ * @since 1.6.0
+ */
+public final class DataSourcePathResolver extends DataSourceBaseResolver {
+
+    /** The base directory of the resource when resolving relative paths */
+    private final Path baseDir;
+
+    /**
+     * Constructs a new instance.
+     */
+    public DataSourcePathResolver() {
+        baseDir = Paths.get(".");
+    }
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param baseDir the base directory of the resource when resolving 
relative paths
+     */
+    public DataSourcePathResolver(final Path baseDir) {
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * Constructs a new instance.
+     *
+     * @param baseDir the base directory of the resource when resolving 
relative paths
+     * @param lenient shall we ignore resources not found or complain with an 
exception
+     */
+    public DataSourcePathResolver(final Path baseDir, final boolean lenient) {
+        super(lenient);
+        this.baseDir = baseDir;
+    }
+
+    /**
+     * Gets the base directory used for resolving relative resource locations.
+     *
+     * @return the baseUrl
+     */
+    public Path getBaseDir() {
+        return baseDir;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DataSource resolve(final String resourceLocation) throws 
IOException {
+        return resolve(resourceLocation, isLenient());
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public DataSource resolve(final String resourceLocation, final boolean 
isLenient) throws IOException {
+        Path file;
+        DataSource result = null;
+
+        if (!isCid(resourceLocation)) {
+            file = Paths.get(resourceLocation);
+
+            if (!file.isAbsolute()) {
+                file = getBaseDir() != null ? 
getBaseDir().resolve(resourceLocation) : Paths.get(resourceLocation);
+            }
+
+            if (Files.exists(file)) {
+                result = new PathDataSource(file);
+            } else if (!isLenient) {
+                throw new IOException("Cant resolve the following file 
resource :" + file.toAbsolutePath());
+            }
+        }
+
+        return result;
+    }
+}
diff --git 
a/src/test/java/org/apache/commons/mail/resolver/DataSourcePathResolverTest.java
 
b/src/test/java/org/apache/commons/mail/resolver/DataSourcePathResolverTest.java
new file mode 100644
index 0000000..34759bb
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/mail/resolver/DataSourcePathResolverTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.commons.mail.resolver;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.file.Paths;
+
+import org.apache.commons.mail.DataSourceResolver;
+import org.junit.jupiter.api.Test;
+
+/**
+ * JUnit test case for DateSourceResolver.
+ */
+public class DataSourcePathResolverTest extends AbstractDataSourceResolverTest 
{
+
+    @Test
+    public void testResolveLenient() throws Exception {
+        final DataSourceResolver dataSourceResolver = new 
DataSourcePathResolver(Paths.get("./src/test/resources"), true);
+        assertEquals(IMG_SIZE, 
toByteArray(dataSourceResolver.resolve("images/asf_logo_wide.gif")).length);
+        assertEquals(IMG_SIZE, 
toByteArray(dataSourceResolver.resolve("./images/asf_logo_wide.gif")).length);
+        assertEquals(IMG_SIZE, 
toByteArray(dataSourceResolver.resolve("../resources/images/asf_logo_wide.gif")).length);
+        
assertNull(toByteArray(dataSourceResolver.resolve("/images/does-not-exist.gif")));
+        assertNull(dataSourceResolver.resolve("./images/does-not-exist.gif"));
+    }
+
+    @Test
+    public void testResolveStrict() throws Exception {
+        final DataSourceResolver dataSourceResolver = new 
DataSourcePathResolver(Paths.get("."), false);
+        
assertNotNull(dataSourceResolver.resolve("./src/test/resources/images/asf_logo_wide.gif"));
+
+        assertThrows(IOException.class, () -> 
dataSourceResolver.resolve("asf_logo_wide.gif"));
+    }
+
+}

Reply via email to