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