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