001    package org.apache.fulcrum.parser;
002    
003    
004    /*
005     * Licensed to the Apache Software Foundation (ASF) under one
006     * or more contributor license agreements.  See the NOTICE file
007     * distributed with this work for additional information
008     * regarding copyright ownership.  The ASF licenses this file
009     * to you under the Apache License, Version 2.0 (the
010     * "License"); you may not use this file except in compliance
011     * with the License.  You may obtain a copy of the License at
012     *
013     *   http://www.apache.org/licenses/LICENSE-2.0
014     *
015     * Unless required by applicable law or agreed to in writing,
016     * software distributed under the License is distributed on an
017     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
018     * KIND, either express or implied.  See the License for the
019     * specific language governing permissions and limitations
020     * under the License.
021     */
022    
023    
024    import java.util.List;
025    
026    import javax.servlet.http.HttpServletRequest;
027    
028    import org.apache.avalon.framework.configuration.Configurable;
029    import org.apache.avalon.framework.configuration.Configuration;
030    import org.apache.avalon.framework.configuration.ConfigurationException;
031    import org.apache.avalon.framework.logger.AbstractLogEnabled;
032    import org.apache.avalon.framework.logger.LogEnabled;
033    import org.apache.avalon.framework.service.ServiceException;
034    import org.apache.avalon.framework.service.ServiceManager;
035    import org.apache.avalon.framework.service.Serviceable;
036    import org.apache.commons.lang.StringUtils;
037    import org.apache.fulcrum.pool.PoolException;
038    import org.apache.fulcrum.pool.PoolService;
039    import org.apache.fulcrum.upload.UploadService;
040    
041    
042    /**
043     * The DefaultParserService provides the efault implementation
044     * of a {@link ParserService}.
045     * 
046     * @author <a href="mailto:tv@apache.org">Thomas Vandahl</a>
047     * @version $Id: BaseValueParser.java 542062 2007-05-28 00:29:43Z seade $
048     */
049    public class DefaultParserService
050        extends AbstractLogEnabled
051        implements ParserService,
052                   Configurable, Serviceable
053    {
054        /** The folding from the configuration */
055        private int folding = URL_CASE_FOLDING_NONE;
056    
057        /** The automaticUpload setting from the configuration */
058        private boolean automaticUpload = AUTOMATIC_DEFAULT;
059    
060        /**
061         * The parameter encoding to use when parsing parameter strings
062         */
063        private String parameterEncoding = PARAMETER_ENCODING_DEFAULT;
064    
065        /**
066         * The upload service component to use
067         */
068        private UploadService uploadService = null;
069    
070        /**
071         * The pool service component to use
072         */
073        private PoolService poolService = null;
074        
075        /**
076         * Get the character encoding that will be used by this ValueParser.
077         */
078        public String getParameterEncoding()
079        {
080            return parameterEncoding;
081        }
082    
083        /**
084         * Trims the string data and applies the conversion specified in
085         * the property given by URL_CASE_FOLDING.  It returns a new
086         * string so that it does not destroy the value data.
087         *
088         * @param value A String to be processed.
089         * @return A new String converted to lowercase and trimmed.
090         */
091        public String convert(String value)
092        {
093            return convertAndTrim(value);
094        }
095    
096        /**
097         * Convert a String value according to the url-case-folding property.
098         *
099         * @param value the String to convert
100         *
101         * @return a new String.
102         *
103         */
104        public String convertAndTrim(String value)
105        {
106            return convertAndTrim(value, getUrlFolding());
107        }
108    
109        /**
110         * A static version of the convert method, which
111         * trims the string data and applies the conversion specified in
112         * the property given by URL_CASE_FOLDING.  It returns a new
113         * string so that it does not destroy the value data.
114         *
115         * @param value A String to be processed.
116         * @return A new String converted to lowercase and trimmed.
117         */
118        public String convertAndTrim(String value, int fold)
119        {
120            if(value == null) return "";
121    
122            String tmp = value.trim();
123    
124            switch (fold)
125            {
126                case URL_CASE_FOLDING_NONE:
127                {
128                    break;
129                }
130    
131                case URL_CASE_FOLDING_LOWER:
132                {
133                    tmp = tmp.toLowerCase();
134                    break;
135                }
136    
137                case URL_CASE_FOLDING_UPPER:
138                {
139                    tmp = tmp.toUpperCase();
140                    break;
141                }
142    
143                default:
144                {
145                    getLogger().error("Passed " + fold + " as fold rule, which is illegal!");
146                    break;
147                }
148            }
149            return tmp;
150        }
151    
152        /**
153         * Gets the folding value from the configuration
154         *
155         * @return The current Folding Value
156         */
157        public int getUrlFolding()
158        {
159            return folding;
160        }
161    
162        /**
163         * Gets the automaticUpload value from the configuration
164         *
165         * @return The current automaticUpload Value
166         */
167        public boolean getAutomaticUpload()
168        {
169            return automaticUpload;
170        }
171    
172        /**
173         * Use the UploadService if available to parse the given request 
174         * for uploaded files
175         *
176         * @return A list of {@link org.apache.commons.upload.FileItem}s
177         * 
178         * @throws ServiceException if parsing fails or the UploadService 
179         * is not available
180         */
181        public List parseUpload(HttpServletRequest request) throws ServiceException
182        {
183            if (uploadService == null)
184            {
185                throw new ServiceException(ParserService.ROLE, "UploadService is not available.");
186            }
187            else
188            {
189                return uploadService.parseRequest(request);
190            }
191        }
192        
193        /**
194         * Get a {@link ValueParser} instance from the service. Use the
195         * given Class to create the object.
196         * 
197         * @return An object that implements ValueParser
198         * 
199         * @throws InstantiationException if the instance could not be created
200         */
201        public ValueParser getParser(Class ppClass) throws InstantiationException
202        {
203            ValueParser vp = null;
204            
205            try
206            {
207                vp = (ValueParser) poolService.getInstance(ppClass);
208                
209                if (vp instanceof ParserServiceSupport)
210                {
211                    ((ParserServiceSupport)vp).setParserService(this);
212                }
213                
214                if (vp instanceof LogEnabled)
215                {
216                    ((LogEnabled)vp).enableLogging(getLogger().getChildLogger(ppClass.getName()));
217                }
218                
219            }
220            catch (PoolException pe)
221            {
222                throw new InstantiationException("Parser class '" + ppClass + "' is illegal. " + pe.getMessage());
223            }
224            catch (ClassCastException x)
225            {
226                throw new InstantiationException("Parser class '" + ppClass + "' is illegal. " + x.getMessage());
227            }
228    
229            return vp;
230        }
231    
232        /**
233         * Return a used Parser to the service. This allows for
234         * pooling and recycling
235         * 
236         * @param parser
237         */
238        public void putParser(ValueParser parser)
239        {
240            parser.clear();
241            poolService.putInstance(parser);
242        }
243    
244        /**
245         * Avalon component lifecycle method
246         */
247        public void configure(Configuration conf) throws ConfigurationException
248        {
249            if (folding == URL_CASE_FOLDING_UNSET)
250            {
251                String foldString = conf.getChild(URL_CASE_FOLDING_KEY).getValue(URL_CASE_FOLDING_NONE_VALUE).toLowerCase();
252    
253                folding = URL_CASE_FOLDING_NONE;
254    
255                getLogger().debug("Setting folding from " + foldString);
256    
257                if (StringUtils.isNotEmpty(foldString))
258                {
259                    if (foldString.equals(URL_CASE_FOLDING_NONE_VALUE))
260                    {
261                        folding = URL_CASE_FOLDING_NONE;
262                    }
263                    else if (foldString.equals(URL_CASE_FOLDING_LOWER_VALUE))
264                    {
265                        folding = URL_CASE_FOLDING_LOWER;
266                    }
267                    else if (foldString.equals(URL_CASE_FOLDING_UPPER_VALUE))
268                    {
269                        folding = URL_CASE_FOLDING_UPPER;
270                    }
271                    else
272                    {
273                        getLogger().error("Got " + foldString + " from " + URL_CASE_FOLDING_KEY + " property, which is illegal!");
274                        throw new ConfigurationException("Value " + foldString + " is illegal!");
275                    }
276                }
277            }
278    
279            parameterEncoding = conf.getChild(PARAMETER_ENCODING_KEY)
280                                .getValue(PARAMETER_ENCODING_DEFAULT).toLowerCase();
281    
282            automaticUpload = conf.getAttributeAsBoolean(
283                                AUTOMATIC_KEY,
284                                AUTOMATIC_DEFAULT);
285        }
286    
287        // ---------------- Avalon Lifecycle Methods ---------------------
288        /**
289         * Avalon component lifecycle method
290         */
291        public void service(ServiceManager manager) throws ServiceException
292        {
293            if (manager.hasService(UploadService.ROLE))
294            {
295                uploadService = (UploadService)manager.lookup(UploadService.ROLE);
296            }
297            else
298            {
299                /*
300                 * Automatic parsing of uploaded file items was requested but no
301                 * UploadService is available
302                 */
303                if (getAutomaticUpload())
304                {
305                    throw new ServiceException(ParserService.ROLE,
306                            AUTOMATIC_KEY + " = true requires " +
307                            UploadService.ROLE + " to be available");
308                }
309            }
310    
311            if (manager.hasService(PoolService.ROLE))
312            {
313                poolService = (PoolService)manager.lookup(PoolService.ROLE);
314            }
315            else
316            {
317                throw new ServiceException(ParserService.ROLE,
318                        "Service requires " +
319                        PoolService.ROLE + " to be available");
320            }
321        }
322    }