    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
    018    package org.apache.commons.net.ftp.parser;
    019
    020    import org.apache.commons.net.ftp.Configurable;
    021    import org.apache.commons.net.ftp.FTPClientConfig;
    022    import org.apache.commons.net.ftp.FTPFileEntryParser;
    023
    024
    025    /**
    026     * This is the default implementation of the
    027     * FTPFileEntryParserFactory interface.  This is the
    028     * implementation that will be used by
    029     * org.apache.commons.net.ftp.FTPClient.listFiles()
    030     * if no other implementation has been specified.
    031     *
    032     * @see org.apache.commons.net.ftp.FTPClient#listFiles
    033     * @see org.apache.commons.net.ftp.FTPClient#setParserFactory
    034     */
    035    public class DefaultFTPFileEntryParserFactory
    036        implements FTPFileEntryParserFactory
    037    {
    038        private FTPClientConfig config = null;
    039
    040        /**
    041         * This default implementation of the FTPFileEntryParserFactory
    042         * interface works according to the following logic:
    043         * First it attempts to interpret the supplied key as a fully
    044         * qualified classname of a class implementing the
    045         * FTPFileEntryParser interface.  If that succeeds, a parser
    046         * object of this class is instantiated and is returned;
    047         * otherwise it attempts to interpret the key as an identirier
    048         * commonly used by the FTP SYST command to identify systems.
    049         * <p/>
    050         * If <code>key</code> is not recognized as a fully qualified
    051         * classname known to the system, this method will then attempt
    052         * to see whether it <b>contains</b> a string identifying one of
    053         * the known parsers.  This comparison is <b>case-insensitive</b>.
    054         * The intent here is where possible, to select as keys strings
    055         * which are returned by the SYST command on the systems which
    056         * the corresponding parser successfully parses.  This enables
    057         * this factory to be used in the auto-detection system.
    058         * <p/>
    059         *
    060         * @param key    should be a fully qualified classname corresponding to
    061         *               a class implementing the FTPFileEntryParser interface<br/>
    062         *               OR<br/>
    063         *               a string containing (case-insensitively) one of the
    064         *               following keywords:
    065         *               <ul>
    066         *               <li>{@link FTPClientConfig#SYST_UNIX UNIX}</li>
    067         *               <li>{@link FTPClientConfig#SYST_NT WINDOWS}</li>
    068         *               <li>{@link FTPClientConfig#SYST_OS2 OS/2}</li>
    069         *               <li>{@link FTPClientConfig#SYST_OS400 OS/400}</li>
    070         *               <li>{@link FTPClientConfig#SYST_VMS VMS}</li>
    071         *               <li>{@link FTPClientConfig#SYST_MVS MVS}</li>
    072         *               <li>{@link FTPClientConfig#SYST_NETWARE NETWARE}</li>
    073         *               </ul>
    074         * @return the FTPFileEntryParser corresponding to the supplied key.
    075         * @throws ParserInitializationException thrown if for any reason the factory cannot resolve
    076         *                   the supplied key into an FTPFileEntryParser.
    077         * @see FTPFileEntryParser
    078         */
    079        public FTPFileEntryParser createFileEntryParser(String key)
    080        {
    081            if (key == null)
    082                throw new ParserInitializationException("Parser key cannot be null");
    083
    084            Class<?> parserClass = null;
    085            FTPFileEntryParser parser = null;
    086            try
    087            {
    088                parserClass = Class.forName(key);
    089                try {
    090                    parser = (FTPFileEntryParser) parserClass.newInstance();
    091                } catch (ClassCastException e) {
    092                    throw new ParserInitializationException(parserClass.getName()
    093                        + " does not implement the interface "
    094                        + "org.apache.commons.net.ftp.FTPFileEntryParser.", e);
    095                }
    096            }
    097            catch (ClassNotFoundException e)
    098            {
    099                try
    100                {
    101                    String ukey = key.toUpperCase(java.util.Locale.ENGLISH);
    102                    if (ukey.indexOf(FTPClientConfig.SYST_UNIX) >= 0)
    103                    {
    104                        parser = createUnixFTPEntryParser();
    105                    }
    106                    else if (ukey.indexOf(FTPClientConfig.SYST_VMS) >= 0)
    107                    {
    108                        parser = createVMSVersioningFTPEntryParser();
    109                    }
    110                    else if (ukey.indexOf(FTPClientConfig.SYST_NT) >= 0)
    111                    {
    112                        parser = createNTFTPEntryParser();
    113                    }
    114                    else if (ukey.indexOf(FTPClientConfig.SYST_OS2) >= 0)
    115                    {
    116                        parser = createOS2FTPEntryParser();
    117                    }
    118                    else if (ukey.indexOf(FTPClientConfig.SYST_OS400) >= 0 ||
    119                            ukey.indexOf(FTPClientConfig.SYST_AS400) >= 0)
    120                    {
    121                        parser = createOS400FTPEntryParser();
    122                    }
    123                    else if (ukey.indexOf(FTPClientConfig.SYST_MVS) >= 0)
    124                    {
    125                        parser = createMVSEntryParser();
    126                    }
    127                    else if (ukey.indexOf(FTPClientConfig.SYST_NETWARE) >= 0)
    128                    {
    129                        parser = createNetwareFTPEntryParser();
    130                    }
    131                    else if (ukey.indexOf(FTPClientConfig.SYST_L8) >= 0)
    132                    {
    133                        // L8 normally means Unix, but move it to the end for some L8 systems that aren't.
    134                        // This check should be last!
    135                        parser = createUnixFTPEntryParser();
    136                    }
    137                    else
    138                    {
    139                        throw new ParserInitializationException("Unknown parser type: " + key);
    140                    }
    141                }
    142                // TODO can this happen?
    143                catch (NoClassDefFoundError nf) {
    144                        throw new ParserInitializationException("Error initializing parser", nf);
    145                }
    146
    147            }
    148            catch (NoClassDefFoundError e)
    149            {
    150                throw new ParserInitializationException("Error initializing parser", e);
    151            }
    152            catch (ParserInitializationException e) // Don't rewrap exception
    153            {
    154                throw e;
    155            }
    156            catch (Throwable e)
    157            {
    158                throw new ParserInitializationException("Error initializing parser", e);
    159            }
    160
    161            if (parser instanceof Configurable) {
    162                ((Configurable)parser).configure(this.config);
    163            }
    164            return parser;
    165        }
    166
    167        /**
    168         * <p>Implementation extracts a key from the supplied
    169         * {@link  FTPClientConfig FTPClientConfig}
    170         * parameter and creates an object implementing the
    171         * interface FTPFileEntryParser and uses the supplied configuration
    172         * to configure it.
    173         * </p><p>
    174         * Note that this method will generally not be called in scenarios
    175         * that call for autodetection of parser type but rather, for situations
    176         * where the user knows that the server uses a non-default configuration
    177         * and knows what that configuration is.
    178         * </p>
    179         * @param config  A {@link  FTPClientConfig FTPClientConfig}
    180         * used to configure the parser created
    181         *
    182         * @return the @link  FTPFileEntryParser FTPFileEntryParser} so created.
    183         * @exception ParserInitializationException
    184         *                   Thrown on any exception in instantiation
    185         * @since 1.4
    186         */
    187        public FTPFileEntryParser createFileEntryParser(FTPClientConfig config)
    188        throws ParserInitializationException
    189        {
    190            this.config = config;
    191            String key = config.getServerSystemKey();
    192            return createFileEntryParser(key);
    193        }
    194
    195
    196        public FTPFileEntryParser createUnixFTPEntryParser()
    197        {
    198            return new UnixFTPEntryParser();
    199        }
    200
    201        public FTPFileEntryParser createVMSVersioningFTPEntryParser()
    202        {
    203            return new VMSVersioningFTPEntryParser();
    204        }
    205
    206        public FTPFileEntryParser createNetwareFTPEntryParser() {
    207            return new NetwareFTPEntryParser();
    208        }
    209
    210        public FTPFileEntryParser createNTFTPEntryParser()
    211        {
    212            if (config != null && FTPClientConfig.SYST_NT.equals(
    213                    config.getServerSystemKey()))
    214            {
    215                return new NTFTPEntryParser();
    216            } else {
    217                return new CompositeFileEntryParser(new FTPFileEntryParser[]
    218                       {
    219                           new NTFTPEntryParser(),
    220                           new UnixFTPEntryParser()
    221                       });
    222            }
    223        }
    224
    225         public FTPFileEntryParser createOS2FTPEntryParser()
    226        {
    227            return new OS2FTPEntryParser();
    228        }
    229
    230        public FTPFileEntryParser createOS400FTPEntryParser()
    231        {
    232            if (config != null &&
    233                    FTPClientConfig.SYST_OS400.equals(config.getServerSystemKey()))
    234            {
    235                return new OS400FTPEntryParser();
    236            } else {
    237                return new CompositeFileEntryParser(new FTPFileEntryParser[]
    238                    {
    239                        new OS400FTPEntryParser(),
    240                        new UnixFTPEntryParser()
    241                    });
    242            }
    243        }
    244
    245        public FTPFileEntryParser createMVSEntryParser()
    246        {
    247            return new MVSFTPEntryParser();
    248        }
    249
    250    }
    251