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