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 1632033 2014-10-15 13:53:24Z 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                    throw new IOException("The following class path resource was not found : " + resourceLocation);
109                }
110            }
111
112
113            return result;
114        }
115        catch (final IOException e)
116        {
117            if (isLenient)
118            {
119                return null;
120            }
121            throw e;
122        }
123    }
124
125    /**
126     * Returns the resource name for a given resource location.
127     *
128     * @param resourceLocation the resource location
129     * @return {@link #getClassPathBase()} + {@code resourceLocation}
130     * @see #getClassPathBase()
131     */
132    private String getResourceName(final String resourceLocation)
133    {
134        return (getClassPathBase() + resourceLocation).replaceAll("//", "/");
135    }
136}