    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     */
    017    package org.apache.commons.configuration;
    018
    019    import org.apache.commons.vfs2.FileObject;
    020    import org.apache.commons.vfs2.FileName;
    021    import org.apache.commons.vfs2.VFS;
    022    import org.apache.commons.vfs2.FileSystemManager;
    023    import org.apache.commons.vfs2.FileContent;
    024    import org.apache.commons.vfs2.FileSystemException;
    025    import org.apache.commons.vfs2.FileType;
    026    import org.apache.commons.vfs2.FileSystemOptions;
    027    import org.apache.commons.vfs2.FileSystemConfigBuilder;
    028    import org.apache.commons.vfs2.provider.UriParser;
    029
    030    import java.io.InputStream;
    031    import java.io.OutputStream;
    032    import java.io.File;
    033    import java.io.IOException;
    034    import java.net.URL;
    035    import java.net.URLStreamHandler;
    036    import java.net.MalformedURLException;
    037    import java.net.URLConnection;
    038    import java.util.Map;
    039    import java.util.Iterator;
    040    import java.lang.reflect.Method;
    041
    042    /**
    043     * FileSystem that uses Commons VFS
    044     * @since 1.7
    045     * @author <a
    046     * href="http://commons.apache.org/configuration/team-list.html">Commons Configuration team</a>
    047     */
    048    public class VFSFileSystem extends DefaultFileSystem
    049    {
    050        public VFSFileSystem()
    051        {
    052        }
    053
    054        public InputStream getInputStream(String basePath, String fileName)
    055            throws ConfigurationException
    056        {
    057            try
    058            {
    059                FileSystemManager manager = VFS.getManager();
    060                FileName path;
    061                if (basePath != null)
    062                {
    063                    FileName base = manager.resolveURI(basePath);
    064                    path = manager.resolveName(base, fileName);
    065                }
    066                else
    067                {
    068                    FileName file = manager.resolveURI(fileName);
    069                    FileName base = file.getParent();
    070                    path = manager.resolveName(base, file.getBaseName());
    071                }
    072                FileSystemOptions opts = getOptions(path.getScheme());
    073                FileObject file = (opts == null) ? manager.resolveFile(path.getURI())
    074                        : manager.resolveFile(path.getURI(), opts);
    075                FileContent content = file.getContent();
    076                if (content == null)
    077                {
    078                    String msg = "Cannot access content of " + file.getName().getFriendlyURI();
    079                    throw new ConfigurationException(msg);
    080                }
    081                return content.getInputStream();
    082            }
    083            catch (ConfigurationException e)
    084            {
    085                throw e;
    086            }
    087            catch (Exception e)
    088            {
    089                throw new ConfigurationException("Unable to load the configuration file " + fileName, e);
    090            }
    091        }
    092
    093        public InputStream getInputStream(URL url) throws ConfigurationException
    094        {
    095            FileObject file;
    096            try
    097            {
    098                FileSystemOptions opts = getOptions(url.getProtocol());
    099                file = (opts == null) ? VFS.getManager().resolveFile(url.toString())
    100                        : VFS.getManager().resolveFile(url.toString(), opts);
    101                if (file.getType() != FileType.FILE)
    102                {
    103                    throw new ConfigurationException("Cannot load a configuration from a directory");
    104                }
    105                FileContent content = file.getContent();
    106                if (content == null)
    107                {
    108                    String msg = "Cannot access content of " + file.getName().getFriendlyURI();
    109                    throw new ConfigurationException(msg);
    110                }
    111                return content.getInputStream();
    112            }
    113            catch (FileSystemException fse)
    114            {
    115                String msg = "Unable to access " + url.toString();
    116                throw new ConfigurationException(msg, fse);
    117            }
    118        }
    119
    120        public OutputStream getOutputStream(URL url) throws ConfigurationException
    121        {
    122            try
    123            {
    124                FileSystemOptions opts = getOptions(url.getProtocol());
    125                FileSystemManager fsManager = VFS.getManager();
    126                FileObject file = (opts == null) ? fsManager.resolveFile(url.toString())
    127                        : fsManager.resolveFile(url.toString(), opts);
    128                // throw an exception if the target URL is a directory
    129                if (file == null || file.getType() == FileType.FOLDER)
    130                {
    131                    throw new ConfigurationException("Cannot save a configuration to a directory");
    132                }
    133                FileContent content = file.getContent();
    134
    135                if (content == null)
    136                {
    137                    throw new ConfigurationException("Cannot access content of " + url);
    138                }
    139                return content.getOutputStream();
    140            }
    141            catch (FileSystemException fse)
    142            {
    143                throw new ConfigurationException("Unable to access " + url, fse);
    144            }
    145        }
    146
    147        public String getPath(File file, URL url, String basePath, String fileName)
    148        {
    149            if (file != null)
    150            {
    151                return super.getPath(file, url, basePath, fileName);
    152            }
    153            try
    154            {
    155                FileSystemManager fsManager = VFS.getManager();
    156                if (url != null)
    157                {
    158                    FileName name = fsManager.resolveURI(url.toString());
    159                    if (name != null)
    160                    {
    161                        return name.toString();
    162                    }
    163                }
    164
    165                if (UriParser.extractScheme(fileName) != null)
    166                {
    167                    return fileName;
    168                }
    169                else if (basePath != null)
    170                {
    171                    FileName base = fsManager.resolveURI(basePath);
    172                    return fsManager.resolveName(base, fileName).getURI();
    173                }
    174                else
    175                {
    176                    FileName name = fsManager.resolveURI(fileName);
    177                    FileName base = name.getParent();
    178                    return fsManager.resolveName(base, name.getBaseName()).getURI();
    179                }
    180            }
    181            catch (FileSystemException fse)
    182            {
    183                fse.printStackTrace();
    184                return null;
    185            }
    186        }
    187
    188        public String getBasePath(String path)
    189        {
    190            if (UriParser.extractScheme(path) == null)
    191            {
    192                return super.getBasePath(path);
    193            }
    194            try
    195            {
    196                FileSystemManager fsManager = VFS.getManager();
    197                FileName name = fsManager.resolveURI(path);
    198                return name.getParent().getURI();
    199            }
    200            catch (FileSystemException fse)
    201            {
    202                fse.printStackTrace();
    203                return null;
    204            }
    205        }
    206
    207        public String getFileName(String path)
    208        {
    209            if (UriParser.extractScheme(path) == null)
    210            {
    211                return super.getFileName(path);
    212            }
    213            try
    214            {
    215                FileSystemManager fsManager = VFS.getManager();
    216                FileName name = fsManager.resolveURI(path);
    217                return name.getBaseName();
    218            }
    219            catch (FileSystemException fse)
    220            {
    221                fse.printStackTrace();
    222                return null;
    223            }
    224        }
    225
    226        public URL getURL(String basePath, String file) throws MalformedURLException
    227        {
    228            if ((basePath != null && UriParser.extractScheme(basePath) == null)
    229                || (basePath == null && UriParser.extractScheme(file) == null))
    230            {
    231                return super.getURL(basePath, file);
    232            }
    233            try
    234            {
    235                FileSystemManager fsManager = VFS.getManager();
    236
    237                FileName path;
    238                if (basePath != null && UriParser.extractScheme(file) == null)
    239                {
    240                    FileName base = fsManager.resolveURI(basePath);
    241                    path = fsManager.resolveName(base, file);
    242                }
    243                else
    244                {
    245                    path = fsManager.resolveURI(file);
    246                }
    247
    248                URLStreamHandler handler = new VFSURLStreamHandler(path);
    249                return new URL(null, path.getURI(), handler);
    250            }
    251            catch (FileSystemException fse)
    252            {
    253                throw new ConfigurationRuntimeException("Could not parse basePath: " + basePath
    254                    + " and fileName: " + file, fse);
    255            }
    256        }
    257
    258        public URL locateFromURL(String basePath, String fileName)
    259        {
    260            String fileScheme = UriParser.extractScheme(fileName);
    261
    262            // Use DefaultFileSystem if basePath and fileName don't have a scheme.
    263            if ((basePath == null || UriParser.extractScheme(basePath) == null) && fileScheme == null)
    264            {
    265                return super.locateFromURL(basePath, fileName);
    266            }
    267            try
    268            {
    269                FileSystemManager fsManager = VFS.getManager();
    270
    271                FileObject file;
    272                // Only use the base path if the file name doesn't have a scheme.
    273                if (basePath != null && fileScheme == null)
    274                {
    275                    String scheme = UriParser.extractScheme(basePath);
    276                    FileSystemOptions opts = (scheme != null) ? getOptions(scheme) : null;
    277                    FileObject base = (opts == null) ? fsManager.resolveFile(basePath)
    278                            : fsManager.resolveFile(basePath, opts);
    279                    if (base.getType() == FileType.FILE)
    280                    {
    281                        base = base.getParent();
    282                    }
    283
    284                    file = fsManager.resolveFile(base, fileName);
    285                }
    286                else
    287                {
    288                    FileSystemOptions opts = (fileScheme != null) ? getOptions(fileScheme) : null;
    289                    file = (opts == null) ? fsManager.resolveFile(fileName)
    290                            : fsManager.resolveFile(fileName, opts);
    291                }
    292
    293                if (!file.exists())
    294                {
    295                    return null;
    296                }
    297                FileName path = file.getName();
    298                URLStreamHandler handler = new VFSURLStreamHandler(path);
    299                return new URL(null, path.getURI(), handler);
    300            }
    301            catch (FileSystemException fse)
    302            {
    303                return null;
    304            }
    305            catch (MalformedURLException ex)
    306            {
    307                return null;
    308            }
    309        }
    310
    311        private FileSystemOptions getOptions(String scheme)
    312        {
    313            FileSystemOptions opts = new FileSystemOptions();
    314            FileSystemConfigBuilder builder;
    315            try
    316            {
    317                builder = VFS.getManager().getFileSystemConfigBuilder(scheme);
    318            }
    319            catch (Exception ex)
    320            {
    321                return null;
    322            }
    323            FileOptionsProvider provider = getFileOptionsProvider();
    324            if (provider != null)
    325            {
    326                Map map = provider.getOptions();
    327                if (map == null)
    328                {
    329                    return null;
    330                }
    331                Iterator iter = map.entrySet().iterator();
    332                int count = 0;
    333                while (iter.hasNext())
    334                {
    335                    Map.Entry entry = (Map.Entry) iter.next();
    336                    try
    337                    {
    338                        String key = (String) entry.getKey();
    339                        if (FileOptionsProvider.CURRENT_USER.equals(key))
    340                        {
    341                            key = "creatorName";
    342                        }
    343                        setProperty(builder, opts, key, entry.getValue());
    344                        ++count;
    345                    }
    346                    catch (Exception ex)
    347                    {
    348                        // Ignore an incorrect property.
    349                        continue;
    350                    }
    351                }
    352                if (count > 0)
    353                {
    354                    return opts;
    355                }
    356            }
    357            return null;
    358
    359        }
    360
    361        private void setProperty(FileSystemConfigBuilder builder, FileSystemOptions options,
    362                                 String key, Object value)
    363        {
    364            String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
    365            Class[] paramTypes = new Class[2];
    366            paramTypes[0] = FileSystemOptions.class;
    367            paramTypes[1] = value.getClass();
    368
    369            try
    370            {
    371                Method method = builder.getClass().getMethod(methodName, paramTypes);
    372                Object[] params = new Object[2];
    373                params[0] = options;
    374                params[1] = value;
    375                method.invoke(builder, params);
    376            }
    377            catch (Exception ex)
    378            {
    379                return;
    380            }
    381
    382        }
    383
    384        /**
    385         * Stream handler required to create URL.
    386         */
    387        private static class VFSURLStreamHandler extends URLStreamHandler
    388        {
    389            /** The Protocol used */
    390            private final String protocol;
    391
    392            public VFSURLStreamHandler(FileName file)
    393            {
    394                this.protocol = file.getScheme();
    395            }
    396
    397            protected URLConnection openConnection(URL url) throws IOException
    398            {
    399                throw new IOException("VFS URLs can only be used with VFS APIs");
    400            }
    401        }
    402    }