001    /*
002     *  Copyright 2004 The Apache Software Foundation
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.apache.commons.convert.conversion;
017    
018    import org.apache.commons.convert.Conversion;
019    import org.apache.commons.convert.ConversionFactory;
020    import org.apache.commons.convert.Converter;
021    
022    /**
023     * A utility class for decorating conversions and factories with default value behaviour.
024     * <p>
025     * Each public static method on this class will decorate the input conversion/factory
026     * with additional behaviour. Depending on the method it may return a default value in
027     * the case of an exception or null value
028     * <p>
029     * To use this facility, create an instance of the conversion/factory as normal.
030     * Then pass it to one of the static methods on this class.
031     * Finally add it as per normal to the <code>ConverterRegistry</code>.
032     * 
033     * @author Stephen Colebourne
034     * @author Oliver Heger
035     * @version $Id: DefaultValueDecorator.java 155441 2005-02-26 13:19:22Z dirkv $
036     * @since 1.0
037     */
038    public class DefaultValueDecorator {
039    
040        /**
041         * Restricted constructor.
042         */
043        protected DefaultValueDecorator() {
044        }
045    
046        //-----------------------------------------------------------------------
047        /**
048         * Creates a Conversion that decorates the original and adds behaviour to
049         * return a default value when the conversion results in null.
050         * 
051         * @param conversion  the conversion to decorate, not null
052         * @param defaultValue  the value to return if conversion result is null
053         * @return the decorated conversion
054         */
055        public static Conversion defaultNullResult(Conversion conversion, Object defaultValue) {
056            checkNotNull(conversion);
057            return new DefaultNullResultConversion(conversion, defaultValue);
058        }
059    
060        /**
061         * Creates a Conversion that decorates the original and adds behaviour to
062         * return a default value when the conversion input is null.
063         * 
064         * @param conversion  the conversion to decorate, not null
065         * @param defaultValue  the value to return if conversion input is null
066         * @return the decorated conversion
067         */
068        public static Conversion defaultNullInput(Conversion conversion, Object defaultValue) {
069            checkNotNull(conversion);
070            return new DefaultNullInputConversion(conversion, defaultValue);
071        }
072    
073        /**
074         * Creates a Conversion that decorates the original and adds behaviour to
075         * return a default value when the conversion throws an exception.
076         * 
077         * @param conversion  the conversion to decorate, not null
078         * @param defaultValue  the value to return if conversion throws an exception
079         * @return the decorated conversion
080         */
081        public static Conversion defaultException(Conversion conversion, Object defaultValue) {
082            checkNotNull(conversion);
083            return new DefaultExceptionConversion(conversion, defaultValue);
084        }
085    
086        /**
087         * Creates a Conversion that decorates the original and adds behaviour to
088         * return a default value for null input, null result and when an exception occurs.
089         * 
090         * @param conversion  the conversion to decorate, not null
091         * @param defaultValue  the default value to return
092         * @return the decorated conversion
093         */
094        public static Conversion defaultNullAndException(Conversion conversion, Object defaultValue) {
095            checkNotNull(conversion);
096            return new DefaultNullExceptionConversion(conversion, defaultValue);
097        }
098    
099        //-----------------------------------------------------------------------
100        /**
101         * Creates a ConversionFactory that decorates the original and adds behaviour to
102         * return a default value when the conversion results in null.
103         * 
104         * @param factory  the factory to decorate, not null
105         * @param defaultValue  the value to return if conversion result is null
106         * @return the decorated factory
107         */
108        public static ConversionFactory defaultNullResult(ConversionFactory factory, Object defaultValue) {
109            checkNotNull(factory);
110            return new DefaultNullResultConversionFactory(factory, defaultValue);
111        }
112    
113        /**
114         * Creates a ConversionFactory that decorates the original and adds behaviour to
115         * return a default value when the conversion input is null.
116         * 
117         * @param factory  the factory to decorate, not null
118         * @param defaultValue  the value to return if conversion input is null
119         * @return the decorated factory
120         */
121        public static ConversionFactory defaultNullInput(ConversionFactory factory, Object defaultValue) {
122            checkNotNull(factory);
123            return new DefaultNullInputConversionFactory(factory, defaultValue);
124        }
125    
126        /**
127         * Creates a ConversionFactory that decorates the original and adds behaviour to
128         * return a default value when the conversion throws an exception.
129         * 
130         * @param factory  the factory to decorate, not null
131         * @param defaultValue  the value to return if conversion throws an exception
132         * @return the decorated factory
133         */
134        public static ConversionFactory defaultException(ConversionFactory factory, Object defaultValue) {
135            checkNotNull(factory);
136            return new DefaultExceptionConversionFactory(factory, defaultValue);
137        }
138    
139        /**
140         * Creates a ConversionFactory that decorates the original and adds behaviour to
141         * return a default value for null input, null result and when an exception occurs.
142         * 
143         * @param factory  the factory to decorate, not null
144         * @param defaultValue  the default value to return
145         * @return the decorated factory
146         */
147        public static ConversionFactory defaultNullAndException(ConversionFactory factory, Object defaultValue) {
148            checkNotNull(factory);
149            return new DefaultNullExceptionConversionFactory(factory, defaultValue);
150        }
151    
152        //-----------------------------------------------------------------------    
153        /**
154         * Checks whether the input conversion is null and throws an exception.
155         * 
156         * @param conversion  the conversion to check
157         */
158        private static void checkNotNull(Conversion conversion) {
159            if (conversion == null) {
160                throw new IllegalArgumentException("Conversion must not be null");
161            }
162        }
163    
164        /**
165         * Checks whether the input factory is null and throws an exception.
166         * 
167         * @param factory  the factory to check
168         */
169        private static void checkNotNull(ConversionFactory factory) {
170            if (factory == null) {
171                throw new IllegalArgumentException("ConversionFactory must not be null");
172            }
173        }
174    
175        //-----------------------------------------------------------------------
176        /**
177         * Abstract base class for default value decorators.
178         */
179        abstract static class AbstractDefaultConversion implements Conversion {
180    
181            /** The decorated conversion */
182            private final Conversion conversion;
183            /** The default value to return */
184            private final Object defaultValue;
185    
186            /**
187             * Constructor.
188             * 
189             * @param conversion  the conversion to decorate, not null
190             * @param defaultValue  the default value to return
191             */
192            AbstractDefaultConversion(Conversion conversion, Object defaultValue) {
193                super();
194                this.conversion = conversion;
195                this.defaultValue = defaultValue;
196            }
197    
198            /**
199             * Returns the type to convert from.
200             * 
201             * @return the Class object representing the class to convert from
202             */
203            public Class getFromType() {
204                return getDecoratedConversion().getFromType();
205            }
206    
207            /**
208             * Returns the type to convert to.
209             * 
210             * @return the Class object representing the class to convert to
211             */
212            public Class getToType() {
213                return getDecoratedConversion().getToType();
214            }
215    
216            /**
217             * Gets the conversion being decorated.
218             * 
219             * @return the decorated conversion
220             */
221            public Conversion getDecoratedConversion() {
222                return conversion;
223            }
224    
225            /**
226             * Gets the default value to be returned.
227             * 
228             * @return the default value
229             */
230            public Object getDefaultValue() {
231                return defaultValue;
232            }
233    
234            /**
235             * Gets a suitable debugging string.
236             * 
237             * @return a debugging string
238             */
239            public String toString() {
240                String str = getDecoratedConversion().toString();
241                return str.substring(0, str.length() - 1) + ",default=" + getDefaultValue() + "]";
242            }
243        }
244    
245        //-----------------------------------------------------------------------
246        /**
247         * Implement the default null result behaviour.
248         */
249        static class DefaultNullResultConversion extends AbstractDefaultConversion {
250    
251            /**
252             * Constructs a null result conversion.
253             * 
254             * @param conversion  the conversion to decorate, not null
255             * @param defaultValue  the value to return if conversion result is null
256             */
257            DefaultNullResultConversion(Conversion conversion, Object defaultValue) {
258                super(conversion, defaultValue);
259            }
260    
261            /**
262             * Performs the conversion by delegating to the original conversion and
263             * then handling the default value.
264             * 
265             * @param value  the object to be converted
266             * @param converter  the associated converter
267             * @return the result of the conversion
268             * @throws Exception if conversion fails, use ConversionException if creating
269             *  a new exception, otherwise just allow exceptions to be thrown
270             */
271            public Object convert(Object value, Converter converter) throws Exception {
272                Object result = getDecoratedConversion().convert(value, converter);
273                if (result == null) {
274                    return getDefaultValue();
275                }
276                return result;
277            }
278        }
279    
280        //-----------------------------------------------------------------------
281        /**
282         * Implement the default null input behaviour.
283         */
284        static class DefaultNullInputConversion extends AbstractDefaultConversion {
285    
286            /**
287             * Constructs a null input conversion.
288             * 
289             * @param conversion  the conversion to decorate, not null
290             * @param defaultValue  the value to return if conversion input is null
291             */
292            DefaultNullInputConversion(Conversion conversion, Object defaultValue) {
293                super(conversion, defaultValue);
294            }
295    
296            /**
297             * Performs the conversion by checking for null, then delegating to the
298             * original conversion.
299             * 
300             * @param value  the object to be converted
301             * @param converter  the associated converter
302             * @return the result of the conversion
303             * @throws Exception if conversion fails, use ConversionException if creating
304             *  a new exception, otherwise just allow exceptions to be thrown
305             */
306            public Object convert(Object value, Converter converter) throws Exception {
307                if (value == null) {
308                    return getDefaultValue();
309                }
310                return getDecoratedConversion().convert(value, converter);
311            }
312        }
313    
314        //-----------------------------------------------------------------------
315        /**
316         * Implement the default on exception behaviour.
317         */
318        static class DefaultExceptionConversion extends AbstractDefaultConversion {
319    
320            /**
321             * Constructs a default on exception conversion.
322             * 
323             * @param conversion  the conversion to decorate, not null
324             * @param defaultValue  the value to return if conversion throws an exception
325             */
326            DefaultExceptionConversion(Conversion conversion, Object defaultValue) {
327                super(conversion, defaultValue);
328            }
329    
330            /**
331             * Performs the conversion by delegating to the original conversion and
332             * handling the default value.
333             * 
334             * @param value  the object to be converted
335             * @param converter  the associated converter
336             * @return the result of the conversion
337             */
338            public Object convert(Object value, Converter converter) {
339                try {
340                    return getDecoratedConversion().convert(value, converter);
341                } catch (Exception ex) {
342                    return getDefaultValue();
343                }
344            }
345        }
346    
347        //-----------------------------------------------------------------------
348        /**
349         * Implement the default on exception behaviour.
350         */
351        static class DefaultNullExceptionConversion extends AbstractDefaultConversion {
352    
353            /**
354             * Constructs a default on nulls and exception conversion.
355             * 
356             * @param conversion  the conversion to decorate, not null
357             * @param defaultValue  the default value to return
358             */
359            DefaultNullExceptionConversion(Conversion conversion, Object defaultValue) {
360                super(conversion, defaultValue);
361            }
362    
363            /**
364             * Performs the conversion by delegating to the original conversion and
365             * handling the default value.
366             * 
367             * @param value  the object to be converted
368             * @param converter  the associated converter
369             * @return the result of the conversion
370             */
371            public Object convert(Object value, Converter converter) {
372                if (value == null) {
373                    return getDefaultValue();
374                }
375                try {
376                    Object result = getDecoratedConversion().convert(value, converter);
377                    if (result == null) {
378                        return getDefaultValue();
379                    }
380                    return result;
381                } catch (Exception ex) {
382                    return getDefaultValue();
383                }
384            }
385        }
386    
387        //-----------------------------------------------------------------------
388        /**
389         * Implement the default null result behaviour.
390         */
391        abstract static class AbstractDefaultConversionFactory implements ConversionFactory {
392    
393            /** The decorated factory */
394            private final ConversionFactory factory;
395            /** The default value to return */
396            private final Object defaultValue;
397    
398            /**
399             * Constructor.
400             * 
401             * @param factory  the factory to decorate, not null
402             * @param defaultValue  the default value to return
403             */
404            AbstractDefaultConversionFactory(ConversionFactory factory, Object defaultValue) {
405                super();
406                this.factory = factory;
407                this.defaultValue = defaultValue;
408            }
409    
410            /**
411             * Gets an indicator as to how well the factory matches.
412             * 
413             * @param value  the value to be converted
414             * @param fromType  the type to be converted from
415             * @param toType  the type to be converted to
416             * @return a percentage value for the appropriateness of this class
417             */
418            public int getMatchPercent(Object value, Class fromType, Class toType) {
419                return getDecoratedConversionFactory().getMatchPercent(value, fromType, toType);
420            }
421    
422            /**
423             * Creates a conversion instance for the specified conversion.
424             * This implementation lets the decorated factory create an instance.
425             * This instance is then decorated with defaulting behaviour.
426             * 
427             * @param value  the value to be converted
428             * @param fromType  the type to convert from
429             * @param toType  the type to convert to
430             * @return a conversion instance
431             */
432            public Conversion getInstance(Object value, Class fromType, Class toType) {
433                Conversion conversion = getDecoratedConversionFactory().getInstance(value, fromType, toType);
434                return createConversion(conversion, getDefaultValue());
435            }
436    
437            /**
438             * Creates a new decorated conversion.
439             * 
440             * @param conversion  the conversion to decorate
441             * @param defaultValue  the default value
442             * @return a new decorated conversion
443             */
444            protected abstract Conversion createConversion(Conversion conversion, Object defaultValue);
445    
446            /**
447             * Gets the factory being decorated.
448             * 
449             * @return the decorated factory
450             */
451            public ConversionFactory getDecoratedConversionFactory() {
452                return factory;
453            }
454    
455            /**
456             * Gets the default value to be returned.
457             * 
458             * @return the default value
459             */
460            public Object getDefaultValue() {
461                return defaultValue;
462            }
463        }
464    
465        //-----------------------------------------------------------------------
466        /**
467         * Implement the default null result behaviour.
468         */
469        static class DefaultNullResultConversionFactory extends AbstractDefaultConversionFactory {
470    
471            /**
472             * Constructs a null result factory.
473             * 
474             * @param factory  the factory to decorate, not null
475             * @param defaultValue  the default value to return
476             */
477            DefaultNullResultConversionFactory(ConversionFactory factory, Object defaultValue) {
478                super(factory, defaultValue);
479            }
480    
481            /**
482             * Creates a new decorated conversion.
483             * 
484             * @param conversion  the conversion to decorate
485             * @param defaultValue  the default value
486             * @return a new decorated conversion
487             */
488            protected Conversion createConversion(Conversion conversion, Object defaultValue) {
489                return new DefaultNullResultConversion(conversion, defaultValue);
490            }
491        }
492    
493        //-----------------------------------------------------------------------
494        /**
495         * Implement the default null input behaviour.
496         */
497        static class DefaultNullInputConversionFactory extends AbstractDefaultConversionFactory {
498    
499            /**
500             * Constructs a null input factory.
501             * 
502             * @param factory  the factory to decorate, not null
503             * @param defaultValue  the default value to return
504             */
505            DefaultNullInputConversionFactory(ConversionFactory factory, Object defaultValue) {
506                super(factory, defaultValue);
507            }
508    
509            /**
510             * Creates a new decorated conversion.
511             * 
512             * @param conversion  the conversion to decorate
513             * @param defaultValue  the default value
514             * @return a new decorated conversion
515             */
516            protected Conversion createConversion(Conversion conversion, Object defaultValue) {
517                return new DefaultNullInputConversion(conversion, defaultValue);
518            }
519        }
520    
521        //-----------------------------------------------------------------------
522        /**
523         * Implement the default on exception behaviour.
524         */
525        static class DefaultExceptionConversionFactory extends AbstractDefaultConversionFactory {
526    
527            /**
528             * Constructs a null result factory.
529             * 
530             * @param factory  the factory to decorate, not null
531             * @param defaultValue  the default value to return
532             */
533            DefaultExceptionConversionFactory(ConversionFactory factory, Object defaultValue) {
534                super(factory, defaultValue);
535            }
536    
537            /**
538             * Creates a new decorated conversion.
539             * 
540             * @param conversion  the conversion to decorate
541             * @param defaultValue  the default value
542             * @return a new decorated conversion
543             */
544            protected Conversion createConversion(Conversion conversion, Object defaultValue) {
545                return new DefaultExceptionConversion(conversion, defaultValue);
546            }
547        }
548    
549        //-----------------------------------------------------------------------
550        /**
551         * Implement the default on nulls and exceptions behaviour.
552         */
553        static class DefaultNullExceptionConversionFactory extends AbstractDefaultConversionFactory {
554    
555            /**
556             * Constructs a null result factory.
557             * 
558             * @param factory  the factory to decorate, not null
559             * @param defaultValue  the default value to return
560             */
561            DefaultNullExceptionConversionFactory(ConversionFactory factory, Object defaultValue) {
562                super(factory, defaultValue);
563            }
564    
565            /**
566             * Creates a new decorated conversion.
567             * 
568             * @param conversion  the conversion to decorate
569             * @param defaultValue  the default value
570             * @return a new decorated conversion
571             */
572            protected Conversion createConversion(Conversion conversion, Object defaultValue) {
573                return new DefaultNullExceptionConversion(conversion, defaultValue);
574            }
575        }
576    
577    }