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 }