View Javadoc

1   /*
2    *  Copyright 2004 The Apache Software Foundation
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.apache.commons.convert.conversion;
17  
18  import org.apache.commons.convert.Conversion;
19  import org.apache.commons.convert.ConversionFactory;
20  import org.apache.commons.convert.Converter;
21  
22  /**
23   * Abstract base class for creating conversion factories.
24   * <p>
25   * This class is especially suited for creating factories as it minimises the effort
26   * required in the subclass.
27   * <p>
28   * To implement a conversion from a class and all of it subclasses, simply extend
29   * this class and implement the {@link #convertValue(Object, Converter)} method.
30   *
31   * @author Stephen Colebourne
32   * @author Oliver Heger
33   * @version $Id: AbstractConversionFactory.java 155441 2005-02-26 13:19:22Z dirkv $
34   * @since 1.0
35   */
36  public abstract class AbstractConversionFactory implements ConversionFactory {
37  
38      /** Useful constant for subclass constructors */
39      protected static final Class STRING_CLASS = String.class;
40  
41      /** The base type to convert from */
42      private final Class baseFromType;
43      /** The type to convert to */
44      private final Class toType;
45  
46      /**
47       * Restricted constructor.
48       * 
49       * @param baseFromType  the base of the class hierarchy to convert from
50       * @param toType  the type to convert to
51       */
52      protected AbstractConversionFactory(Class baseFromType, Class toType) {
53          super();
54          this.baseFromType = baseFromType;
55          this.toType = toType;
56      }
57  
58      //-----------------------------------------------------------------------
59      /**
60       * Checks if this factory matches the request conversion.
61       * <p>
62       * This implementation returns {@link #getMatchPercent()} if the specified
63       * <code>fromType</code> is the same as, or a subclass of, the stored
64       * <code>baseFromType</code> and the specified <code>toType</code> matches
65       * the stored <code>toType</code>.
66       * 
67       * @param value  the value to be converted, read only, may be null
68       * @param fromType  the type to convert from, may be null
69       * @param toType  the type to convert to, may be null
70       * @return 60 if baseFromType or subclass matches fromType and toType matches
71       */
72      public int getMatchPercent(Object value, Class fromType, Class toType) {
73          if (toType == getToType() && getBaseFromType().isAssignableFrom(fromType)) {
74              return getMatchPercent();
75          }
76          return 0;
77      }
78  
79      /**
80       * Gets the percentage to return if a match occurs.
81       * <p>
82       * This implementation returns <code>60</code>.
83       * Subclasses may wish to override and return a different value.
84       * 
85       * @return 60
86       */
87      protected int getMatchPercent() {
88          return 60;
89      }
90  
91      /**
92       * Create a new conversion object for the specified from and to types.
93       * <p>
94       * This implementation returns a <code>Conversion</code> instance that
95       * refers back to this class for its implementation of the actual conversion
96       * via {@link #convertValue(Object, Converter)}.
97       *
98       * @param value  the value to be converted, read only, may be null
99       * @param fromType  the type to convert from, may be null
100      * @param toType  the type to convert to, may be null
101      * @return a Conversion object for repeatedly performing conversions
102      */
103     public Conversion getInstance(Object value, Class fromType, Class toType) {
104         return new FactoryConversion(fromType, toType, this);
105     }
106 
107     /**
108      * Convert the non-null value to another type.
109      * <p>
110      * This method is implemented by subclases to perform the actual conversion.
111      * 
112      * @param value  the input value to be converted, pre-checked to not be null
113      * @param converter  the converter being used, not null
114      * @return the converted value
115      * @throws Exception if conversion fails, use ConversionException if creating
116      *  a new exception, otherwise just allow exceptions to be thrown
117      */
118     protected abstract Object convertValue(Object value, Converter converter) throws Exception;
119 
120     //-----------------------------------------------------------------------
121     /**
122      * The base type to convert from.
123      * This type and its subclasses will be matched by this factory.
124      *
125      * @return the Class object representing the class to convert to
126      */
127     public Class getBaseFromType() {
128         return baseFromType;
129     }
130 
131     /**
132      * The type to convert to.
133      *
134      * @return the Class object representing the class to convert from
135      */
136     public Class getToType() {
137         return toType;
138     }
139 
140     //-----------------------------------------------------------------------
141     /**
142      * Gets a suitable debugging string.
143      * 
144      * @return a debugging string
145      */
146     public String toString() {
147         String from = convertClassToName(getBaseFromType());
148         String to = convertClassToName(getToType());
149         return "ConversionFactory[" + from + "->" + to + "]";
150     }
151 
152     /**
153      * Converts a class to a string name for debugging.
154      * 
155      * @param cls  the class to convert
156      * @return the class name
157      */
158     private String convertClassToName(Class cls) {
159         if (cls == null) {
160             return "null";
161         }
162         String str = cls.getName();
163         int pos = str.lastIndexOf('.');
164         if (str.substring(0, pos).equals("java.lang")) {
165             str = str.substring(pos + 1);
166         }
167         if (str.substring(0, pos).equals("java.util")) {
168             str = str.substring(pos + 1);
169         }
170         return str;
171     }
172 
173     //-----------------------------------------------------------------------
174     /**
175      * Generic conversion implementation that delegates back to the factory.
176      */
177     class FactoryConversion extends AbstractConversion {
178 
179         /** The factory instance that has the actual conversion code */
180         private final AbstractConversionFactory factory;
181 
182         /**
183          * Constructs a Conversion.
184          * 
185          * @param fromType  the type to convert from
186          * @param toType  the type to convert to
187          * @param factory  the factory instance that actually performs the conversion
188          */
189         FactoryConversion(Class fromType, Class toType, AbstractConversionFactory factory) {
190             super(fromType, toType);
191             this.factory = factory;
192         }
193 
194         /**
195          * Convert the non-null value to another type.
196          * <p>
197          * This implementation delegates to the factory method
198          * {@link AbstractConversionFactory#convertValue(Object, Converter)}.
199          * 
200          * @param value  the input value to be converted, pre-checked to not be null
201          * @param converter  the converter being used, not null
202          * @return the converted value
203          * @throws Exception if conversion fails, use ConversionException if creating
204          *  a new exception, otherwise just allow exceptions to be thrown
205          */
206         protected Object convertValue(Object value, Converter converter) throws Exception {
207             return factory.convertValue(value, converter);
208         }
209     }
210 
211 }