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 javax.activation.DataSource;
020import javax.activation.URLDataSource;
021import java.io.IOException;
022import java.net.MalformedURLException;
023import java.net.URL;
024
025/**
026 * Creates a <code>DataSource</code> based on an URL.
027 *
028 * @since 1.3
029 */
030public class DataSourceUrlResolver extends DataSourceBaseResolver
031{
032    /** the base url of the resource when resolving relative paths */
033    private final URL baseUrl;
034
035    /**
036     * Constructor.
037     *
038     * @param baseUrl the base URL used for resolving relative resource locations
039     */
040    public DataSourceUrlResolver(final URL baseUrl)
041    {
042        super();
043        this.baseUrl = baseUrl;
044    }
045
046    /**
047     * Constructor.
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    {
054        super(lenient);
055        this.baseUrl = baseUrl;
056    }
057
058    /**
059     * Get the base URL used for resolving relative resource locations.
060     *
061     * @return the baseUrl
062     */
063    public URL getBaseUrl()
064    {
065        return baseUrl;
066    }
067
068    /** {@inheritDoc} */
069    @Override
070    public DataSource resolve(final String resourceLocation) throws IOException
071    {
072        return resolve(resourceLocation, isLenient());
073    }
074
075    /** {@inheritDoc} */
076    @Override
077    public DataSource resolve(final String resourceLocation, final boolean isLenient) throws IOException
078    {
079        DataSource result = null;
080
081        try
082        {
083            if (!isCid(resourceLocation))
084            {
085                final URL url = createUrl(resourceLocation);
086                result = new URLDataSource(url);
087                result.getInputStream();
088            }
089
090            return result;
091        }
092        catch (final IOException e)
093        {
094            if (isLenient)
095            {
096                return null;
097            }
098            throw e;
099        }
100    }
101
102    /**
103     * Create an URL based on a base URL and a resource location suitable for loading
104     * the resource.
105     *
106     * @param resourceLocation a resource location
107     * @return the corresponding URL
108     * @throws java.net.MalformedURLException creating the URL failed
109     */
110    protected URL createUrl(final String resourceLocation) throws MalformedURLException
111    {
112        // if we get an non-existing base url than the resource can
113        // be directly used to create an URL
114        if (baseUrl == null)
115        {
116            return new URL(resourceLocation);
117        }
118
119        // if we get an non-existing location what we shall do?
120        if (resourceLocation == null || resourceLocation.length() == 0)
121        {
122            throw new IllegalArgumentException("No resource defined");
123        }
124
125        // if we get a stand-alone resource than ignore the base url
126        if (isFileUrl(resourceLocation) || isHttpUrl(resourceLocation))
127        {
128            return new URL(resourceLocation);
129        }
130
131        return new URL(getBaseUrl(), resourceLocation.replaceAll("&amp;", "&"));
132    }
133}