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")); + } + +}