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 }