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