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.FileTypeMap;
021import javax.mail.util.ByteArrayDataSource;
022
023import java.io.IOException;
024import java.io.InputStream;
025
026/**
027 * Creates a <code>DataSource</code> based on an class path.
028 *
029 * @since 1.3
030 * @version $Id: DataSourceClassPathResolver.java 1606709 2014-06-30 12:26:06Z ggregory $
031 */
032public class DataSourceClassPathResolver extends DataSourceBaseResolver
033{
034    /** the base string of the resource relative to the classpath when resolving relative paths */
035    private final String classPathBase;
036
037    /**
038     * Constructor
039     */
040    public DataSourceClassPathResolver()
041    {
042        this.classPathBase = "/";
043    }
044
045    /**
046     * Constructor.
047     *
048     * @param classPathBase a base class path
049     */
050    public DataSourceClassPathResolver(final String classPathBase)
051    {
052        this.classPathBase = classPathBase.endsWith("/") ? classPathBase : classPathBase + "/";
053    }
054
055    /**
056     * Constructor.
057     *
058     * @param classPathBase a base class path
059     * @param lenient shall we ignore resources not found or throw an exception?
060     */
061    public DataSourceClassPathResolver(final String classPathBase, final boolean lenient)
062    {
063        super(lenient);
064        this.classPathBase = classPathBase.endsWith("/") ? classPathBase : classPathBase + "/";
065    }
066
067    /**
068     * @return the classPathBase
069     */
070    public String getClassPathBase()
071    {
072        return classPathBase;
073    }
074
075    /** {@inheritDoc} */
076    public DataSource resolve(final String resourceLocation) throws IOException
077    {
078        return resolve(resourceLocation, isLenient());
079    }
080
081    /** {@inheritDoc} */
082    public DataSource resolve(final String resourceLocation, final boolean isLenient) throws IOException
083    {
084        DataSource result = null;
085
086        try
087        {
088            if (!isCid(resourceLocation) && !isHttpUrl(resourceLocation))
089            {
090                final String mimeType = FileTypeMap.getDefaultFileTypeMap().getContentType(resourceLocation);
091                final String resourceName = getResourceName(resourceLocation);
092                final InputStream is = DataSourceClassPathResolver.class.getResourceAsStream(resourceName);
093
094                if (is != null)
095                {
096                    final ByteArrayDataSource ds = new ByteArrayDataSource(is, mimeType);
097                    // EMAIL-125: set the name of the DataSource to the normalized resource URL
098                    // similar to other DataSource implementations, e.g. FileDataSource, URLDataSource
099                    ds.setName(DataSourceClassPathResolver.class.getResource(resourceName).toString());
100                    result = ds;
101                }
102                else
103                {
104                    if (isLenient)
105                    {
106                        return null;
107                    }
108                    else
109                    {
110                        throw new IOException("The following class path resource was not found : " + resourceLocation);
111                    }
112                }
113            }
114
115
116            return result;
117        }
118        catch (final IOException e)
119        {
120            if (isLenient)
121            {
122                return null;
123            }
124            else
125            {
126                throw e;
127            }
128        }
129    }
130
131    /**
132     * Returns the resource name for a given resource location.
133     *
134     * @param resourceLocation the resource location
135     * @return {@link #getClassPathBase()} + {@code resourceLocation}
136     * @see #getClassPathBase()
137     */
138    private String getResourceName(final String resourceLocation)
139    {
140        return (getClassPathBase() + resourceLocation).replaceAll("//", "/");
141    }
142}