    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.configuration2.io;
    018
    019import java.io.File;
    020import java.io.FileNotFoundException;
    021import java.io.FileOutputStream;
    022import java.io.IOException;
    023import java.io.InputStream;
    024import java.io.OutputStream;
    025import java.net.HttpURLConnection;
    026import java.net.MalformedURLException;
    027import java.net.URL;
    028import java.net.URLConnection;
    029
    030import org.apache.commons.configuration2.ex.ConfigurationException;
    031
    032/**
    033 * FileSystem that uses java.io.File or HttpClient
    034 * @since 1.7
    035 */
    036public class DefaultFileSystem extends FileSystem
    037{
    038    @Override
    039    public InputStream getInputStream(final URL url) throws ConfigurationException
    040    {
    041        // throw an exception if the target URL is a directory
    042        final File file = FileLocatorUtils.fileFromURL(url);
    043        if (file != null && file.isDirectory())
    044        {
    045            throw new ConfigurationException("Cannot load a configuration from a directory");
    046        }
    047
    048        try
    049        {
    050            return url.openStream();
    051        }
    052        catch (final Exception e)
    053        {
    054            throw new ConfigurationException("Unable to load the configuration from the URL " + url, e);
    055        }
    056    }
    057
    058    @Override
    059    public OutputStream getOutputStream(final URL url) throws ConfigurationException
    060    {
    061        // file URLs have to be converted to Files since FileURLConnection is
    062        // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800)
    063        final File file = FileLocatorUtils.fileFromURL(url);
    064        if (file != null)
    065        {
    066            return getOutputStream(file);
    067        }
    068        // for non file URLs save through an URLConnection
    069        OutputStream out;
    070        try
    071        {
    072            final URLConnection connection = url.openConnection();
    073            connection.setDoOutput(true);
    074
    075            // use the PUT method for http URLs
    076            if (connection instanceof HttpURLConnection)
    077            {
    078                final HttpURLConnection conn = (HttpURLConnection) connection;
    079                conn.setRequestMethod("PUT");
    080            }
    081
    082            out = connection.getOutputStream();
    083
    084            // check the response code for http URLs and throw an exception if an error occured
    085            if (connection instanceof HttpURLConnection)
    086            {
    087                out = new HttpOutputStream(out, (HttpURLConnection) connection);
    088            }
    089            return out;
    090        }
    091        catch (final IOException e)
    092        {
    093            throw new ConfigurationException("Could not save to URL " + url, e);
    094        }
    095    }
    096
    097    @Override
    098    public OutputStream getOutputStream(final File file) throws ConfigurationException
    099    {
    100        try
    101        {
    102            // create the file if necessary
    103            createPath(file);
    104            return new FileOutputStream(file);
    105        }
    106        catch (final FileNotFoundException e)
    107        {
    108            throw new ConfigurationException("Unable to save to file " + file, e);
    109        }
    110    }
    111
    112    @Override
    113    public String getPath(final File file, final URL url, final String basePath, final String fileName)
    114    {
    115        String path = null;
    116        // if resource was loaded from jar file may be null
    117        if (file != null)
    118        {
    119            path = file.getAbsolutePath();
    120        }
    121
    122        // try to see if file was loaded from a jar
    123        if (path == null)
    124        {
    125            if (url != null)
    126            {
    127                path = url.getPath();
    128            }
    129            else
    130            {
    131                try
    132                {
    133                    path = getURL(basePath, fileName).getPath();
    134                }
    135                catch (final Exception e)
    136                {
    137                    // simply ignore it and return null
    138                    if (getLogger().isDebugEnabled())
    139                    {
    140                        getLogger().debug(String.format("Could not determine URL for "
    141                                + "basePath = %s, fileName = %s: %s", basePath,
    142                                fileName, e));
    143                    }
    144                }
    145            }
    146        }
    147
    148        return path;
    149    }
    150
    151    @Override
    152    public String getBasePath(final String path)
    153    {
    154        URL url;
    155        try
    156        {
    157            url = getURL(null, path);
    158            return FileLocatorUtils.getBasePath(url);
    159        }
    160        catch (final Exception e)
    161        {
    162            return null;
    163        }
    164    }
    165
    166    @Override
    167    public String getFileName(final String path)
    168    {
    169        URL url;
    170        try
    171        {
    172            url = getURL(null, path);
    173            return FileLocatorUtils.getFileName(url);
    174        }
    175        catch (final Exception e)
    176        {
    177            return null;
    178        }
    179    }
    180
    181
    182    @Override
    183    public URL getURL(final String basePath, final String file) throws MalformedURLException
    184    {
    185        final File f = new File(file);
    186        if (f.isAbsolute()) // already absolute?
    187        {
    188            return FileLocatorUtils.toURL(f);
    189        }
    190
    191        try
    192        {
    193            if (basePath == null)
    194            {
    195                return new URL(file);
    196            }
    197            final URL base = new URL(basePath);
    198            return new URL(base, file);
    199        }
    200        catch (final MalformedURLException uex)
    201        {
    202            return FileLocatorUtils.toURL(FileLocatorUtils.constructFile(basePath, file));
    203        }
    204    }
    205
    206
    207    @Override
    208    public URL locateFromURL(final String basePath, final String fileName)
    209    {
    210        try
    211        {
    212            URL url;
    213            if (basePath == null)
    214            {
    215                return new URL(fileName);
    216                //url = new URL(name);
    217            }
    218            final URL baseURL = new URL(basePath);
    219            url = new URL(baseURL, fileName);
    220
    221            // check if the file exists
    222            InputStream in = null;
    223            try
    224            {
    225                in = url.openStream();
    226            }
    227            finally
    228            {
    229                if (in != null)
    230                {
    231                    in.close();
    232                }
    233            }
    234            return url;
    235        }
    236        catch (final IOException e)
    237        {
    238            if (getLogger().isDebugEnabled())
    239            {
    240                getLogger().debug("Could not locate file " + fileName + " at " + basePath + ": " + e.getMessage());
    241            }
    242            return null;
    243        }
    244    }
    245
    246    /**
    247     * Create the path to the specified file.
    248     *
    249     * @param file the target file
    250     * @throws ConfigurationException if the path cannot be created
    251     */
    252    private void createPath(final File file) throws ConfigurationException
    253    {
    254        if (file != null)
    255        {
    256            // create the path to the file if the file doesn't exist
    257            if (!file.exists())
    258            {
    259                final File parent = file.getParentFile();
    260                if (parent != null && !parent.exists())
    261                {
    262                    if (!parent.mkdirs())
    263                    {
    264                        throw new ConfigurationException("Cannot create path: " + parent);
    265                    }
    266                }
    267            }
    268        }
    269    }
    270    /**
    271     * Wraps the output stream so errors can be detected in the HTTP response.
    272     * @since 1.7
    273     */
    274    private static class HttpOutputStream extends VerifiableOutputStream
    275    {
    276        /** The wrapped OutputStream */
    277        private final OutputStream stream;
    278
    279        /** The HttpURLConnection */
    280        private final HttpURLConnection connection;
    281
    282        public HttpOutputStream(final OutputStream stream, final HttpURLConnection connection)
    283        {
    284            this.stream = stream;
    285            this.connection = connection;
    286        }
    287
    288        @Override
    289        public void write(final byte[] bytes) throws IOException
    290        {
    291            stream.write(bytes);
    292        }
    293
    294        @Override
    295        public void write(final byte[] bytes, final int i, final int i1) throws IOException
    296        {
    297            stream.write(bytes, i, i1);
    298        }
    299
    300        @Override
    301        public void flush() throws IOException
    302        {
    303            stream.flush();
    304        }
    305
    306        @Override
    307        public void close() throws IOException
    308        {
    309            stream.close();
    310        }
    311
    312        @Override
    313        public void write(final int i) throws IOException
    314        {
    315            stream.write(i);
    316        }
    317
    318        @Override
    319        public String toString()
    320        {
    321            return stream.toString();
    322        }
    323
    324        @Override
    325        public void verify() throws IOException
    326        {
    327            if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST)
    328            {
    329                throw new IOException("HTTP Error " + connection.getResponseCode()
    330                        + " " + connection.getResponseMessage());
    331            }
    332        }
    333    }
    334}