001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.mail2.javax.resolver;
018
019import java.io.IOException;
020import java.io.InputStream;
021import java.net.MalformedURLException;
022import java.net.URL;
023
024import javax.activation.DataSource;
025import javax.activation.URLDataSource;
026
027import org.apache.commons.mail2.core.EmailUtils;
028
029/**
030 * Creates a {@code DataSource} based on an URL.
031 *
032 * @since 1.3
033 */
034public class DataSourceUrlResolver extends DataSourceBaseResolver {
035
036    /** The base url of the resource when resolving relative paths */
037    private final URL baseUrl;
038
039    /**
040     * Constructs a new instance.
041     *
042     * @param baseUrl the base URL used for resolving relative resource locations
043     */
044    public DataSourceUrlResolver(final URL baseUrl) {
045        this.baseUrl = baseUrl;
046    }
047
048    /**
049     * Constructs a new instance.
050     *
051     * @param baseUrl the base URL used for resolving relative resource locations
052     * @param lenient shall we ignore resources not found or complain with an exception
053     */
054    public DataSourceUrlResolver(final URL baseUrl, final boolean lenient) {
055        super(lenient);
056        this.baseUrl = baseUrl;
057    }
058
059    /**
060     * Create an URL based on a base URL and a resource location suitable for loading the resource.
061     *
062     * @param resourceLocation a resource location
063     * @return the corresponding URL
064     * @throws java.net.MalformedURLException creating the URL failed
065     */
066    protected URL createUrl(final String resourceLocation) throws MalformedURLException {
067        // if we get an non-existing base url than the resource can
068        // be directly used to create an URL
069        if (baseUrl == null) {
070            return new URL(resourceLocation);
071        }
072        // if we get an non-existing location what we shall do?
073        if (EmailUtils.isEmpty(resourceLocation)) {
074            throw new IllegalArgumentException("No resource defined");
075        }
076        // if we get a stand-alone resource than ignore the base url
077        if (isFileUrl(resourceLocation) || isHttpUrl(resourceLocation)) {
078            return new URL(resourceLocation);
079        }
080        return new URL(getBaseUrl(), resourceLocation.replace("&", "&"));
081    }
082
083    /**
084     * Gets the base URL used for resolving relative resource locations.
085     *
086     * @return the baseUrl
087     */
088    public URL getBaseUrl() {
089        return baseUrl;
090    }
091
092    /** {@inheritDoc} */
093    @Override
094    public DataSource resolve(final String resourceLocation) throws IOException {
095        return resolve(resourceLocation, isLenient());
096    }
097
098    /** {@inheritDoc} */
099    @Override
100    public DataSource resolve(final String resourceLocation, final boolean isLenient) throws IOException {
101        DataSource result = null;
102        try {
103            if (!isCid(resourceLocation)) {
104                result = new URLDataSource(createUrl(resourceLocation));
105                // validate we can read.
106                try (InputStream inputStream = result.getInputStream()) {
107                    inputStream.read();
108                }
109            }
110            return result;
111        } catch (final IOException e) {
112            if (isLenient) {
113                return null;
114            }
115            throw e;
116        }
117    }
118}