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.mail.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
027/**
028 * Creates a {@code DataSource} based on an URL.
029 *
030 * @since 1.3
031 */
032public class DataSourceUrlResolver extends DataSourceBaseResolver {
033
034    /** The base url of the resource when resolving relative paths */
035    private final URL baseUrl;
036
037    /**
038     * Constructs a new instance.
039     *
040     * @param baseUrl the base URL used for resolving relative resource locations
041     */
042    public DataSourceUrlResolver(final URL baseUrl) {
043        this.baseUrl = baseUrl;
044    }
045
046    /**
047     * Constructs a new instance.
048     *
049     * @param baseUrl the base URL used for resolving relative resource locations
050     * @param lenient shall we ignore resources not found or complain with an exception
051     */
052    public DataSourceUrlResolver(final URL baseUrl, final boolean lenient) {
053        super(lenient);
054        this.baseUrl = baseUrl;
055    }
056
057    /**
058     * Create an URL based on a base URL and a resource location suitable for loading the resource.
059     *
060     * @param resourceLocation a resource location
061     * @return the corresponding URL
062     * @throws java.net.MalformedURLException creating the URL failed
063     */
064    protected URL createUrl(final String resourceLocation) throws MalformedURLException {
065        // if we get an non-existing base url than the resource can
066        // be directly used to create an URL
067        if (baseUrl == null) {
068            return new URL(resourceLocation);
069        }
070        // if we get an non-existing location what we shall do?
071        if (resourceLocation == null || resourceLocation.isEmpty()) {
072            throw new IllegalArgumentException("No resource defined");
073        }
074        // if we get a stand-alone resource than ignore the base url
075        if (isFileUrl(resourceLocation) || isHttpUrl(resourceLocation)) {
076            return new URL(resourceLocation);
077        }
078        return new URL(getBaseUrl(), resourceLocation.replace("&", "&"));
079    }
080
081    /**
082     * Gets the base URL used for resolving relative resource locations.
083     *
084     * @return the baseUrl
085     */
086    public URL getBaseUrl() {
087        return baseUrl;
088    }
089
090    /** {@inheritDoc} */
091    @Override
092    public DataSource resolve(final String resourceLocation) throws IOException {
093        return resolve(resourceLocation, isLenient());
094    }
095
096    /** {@inheritDoc} */
097    @Override
098    public DataSource resolve(final String resourceLocation, final boolean isLenient) throws IOException {
099        DataSource result = null;
100        try {
101            if (!isCid(resourceLocation)) {
102                result = new URLDataSource(createUrl(resourceLocation));
103                // validate we can read.
104                try (InputStream inputStream = result.getInputStream()) {
105                    inputStream.read();
106                }
107            }
108            return result;
109        } catch (final IOException e) {
110            if (isLenient) {
111                return null;
112            }
113            throw e;
114        }
115    }
116}