View Javadoc
1 /* 2 * Copyright (C) The Spice Group. All rights reserved. 3 * 4 * This software is published under the terms of the Spice 5 * Software License version 1.1, a copy of which has been included 6 * with this distribution in the LICENSE.txt file. 7 */ 8 package org.codehaus.spice.converter; 9 10 import java.util.ArrayList; 11 import java.util.HashMap; 12 import java.util.Map; 13 import org.codehaus.spice.salt.i18n.Resources; 14 import org.codehaus.spice.salt.i18n.ResourceManager; 15 16 /*** 17 * This is a Converter implementation that is capable of converting between 18 * many different source and destination types, by delegating delegates to 19 * other converters that do the actual work. 20 * 21 * <p>To use this class you must subclass it, and register some converters 22 * using the (@link #registerConverter} method.</p> 23 * 24 * @author Peter Donald 25 * @version $Revision: 1.1 $ $Date: 2003/12/02 08:37:56 $ 26 */ 27 public abstract class AbstractMasterConverter 28 implements Converter 29 { 30 /*** 31 * i18n resources accessor. 32 */ 33 private static final Resources REZ = 34 ResourceManager.getPackageResources( AbstractMasterConverter.class ); 35 36 /*** 37 * Cache of converter instances. This is a map from ConverterFactory to 38 * a Converter instance created by that factory. 39 */ 40 private final Map m_converters = new HashMap(); 41 42 /*** 43 * This holds the mapping between source/destination and ConverterFactory. 44 */ 45 private final HashMap m_mapping = new HashMap(); 46 47 /*** 48 * Convert object to destination type. 49 * 50 * @param destination the destination type 51 * @param original the original object 52 * @param context the context in which to convert 53 * @return the converted object 54 * @throws ConverterException if an error occurs 55 */ 56 public Object convert( final Class destination, 57 final Object original, 58 final Object context ) 59 throws ConverterException 60 { 61 final Class originalClass = original.getClass(); 62 63 if( destination.isAssignableFrom( originalClass ) ) 64 { 65 return original; 66 } 67 68 try 69 { 70 // Determine which converter to use 71 final Converter converter = findConverter( originalClass, destination ); 72 73 // Convert 74 final Object object = converter.convert( destination, original, context ); 75 if( destination.isInstance( object ) ) 76 { 77 return object; 78 } 79 80 final String message = 81 REZ.format( "bad-return-type.error", 82 object.getClass().getName(), 83 destination.getName() ); 84 throw new ConverterException( message ); 85 } 86 catch( final Exception e ) 87 { 88 final String message = 89 REZ.format( "convert.error", 90 originalClass.getName(), 91 destination.getName() ); 92 throw new ConverterException( message, e ); 93 } 94 } 95 96 /*** 97 * Returns the Converter instance to use to convert between a particular 98 * pair of classes. 99 */ 100 private Converter findConverter( final Class originalClass, 101 final Class destination ) 102 throws Exception 103 { 104 // Locate the factory to use 105 final ConverterFactory factory = findConverterFactory( originalClass, destination ); 106 107 // Create the converter 108 Converter converter = (Converter)m_converters.get( factory ); 109 if( converter == null ) 110 { 111 converter = factory.createConverter(); 112 m_converters.put( factory, converter ); 113 } 114 return converter; 115 } 116 117 /*** 118 * Register a converter 119 * 120 * @param factory the factory to use to create converter instances. 121 * @param source the source classname 122 * @param destination the destination classname 123 */ 124 protected void registerConverter( final ConverterFactory factory, 125 final String source, 126 final String destination ) 127 { 128 HashMap map = (HashMap)m_mapping.get( source ); 129 if( null == map ) 130 { 131 map = new HashMap(); 132 m_mapping.put( source, map ); 133 } 134 135 map.put( destination, factory ); 136 137 //Remove instance of converter if it has already been created 138 m_converters.remove( factory ); 139 } 140 141 /*** 142 * Determine the type of converter (represented as a ConverterFactory) to 143 * use to convert between original and destination classes. 144 */ 145 private ConverterFactory findConverterFactory( final Class originalClass, 146 final Class destination ) 147 throws ConverterException 148 { 149 //TODO: Maybe we should search the destination classes hierarchy as well 150 151 // Recursively iterate over the super-types of the original class, 152 // looking for a converter from source type -> destination type. 153 // If more than one is found, choose the most specialised. 154 155 Class bestSrcMatch = null; 156 ConverterFactory matchFactory = null; 157 ArrayList queue = new ArrayList(); 158 queue.add( originalClass ); 159 160 while( !queue.isEmpty() ) 161 { 162 final Class clazz = (Class)queue.remove( 0 ); 163 164 // Add superclass and all interfaces 165 if( clazz.getSuperclass() != null ) 166 { 167 queue.add( clazz.getSuperclass() ); 168 } 169 final Class[] interfaces = clazz.getInterfaces(); 170 for( int i = 0; i < interfaces.length; i++ ) 171 { 172 queue.add( interfaces[ i ] ); 173 } 174 175 // Check if we can convert from current class to destination 176 final ConverterFactory factory = 177 getConverterFactory( clazz.getName(), destination.getName() ); 178 if( factory == null ) 179 { 180 continue; 181 } 182 183 // Choose the more specialised source class 184 if( bestSrcMatch == null || bestSrcMatch.isAssignableFrom( clazz ) ) 185 { 186 bestSrcMatch = clazz; 187 matchFactory = factory; 188 } 189 else if( clazz.isAssignableFrom( bestSrcMatch ) ) 190 { 191 continue; 192 } 193 else 194 { 195 // Duplicate 196 final String message = REZ.getString( "ambiguous-converter.error" ); 197 throw new ConverterException( message ); 198 } 199 } 200 201 // TODO - should cache the (src, dest) -> converter mapping 202 if( bestSrcMatch != null ) 203 { 204 return matchFactory; 205 } 206 207 // Could not find a converter 208 final String message = REZ.getString( "no-converter.error" ); 209 throw new ConverterException( message ); 210 } 211 212 /*** 213 * Retrieve factory for the converter that converts from source to destination. 214 */ 215 private ConverterFactory getConverterFactory( final String source, 216 final String destination ) 217 { 218 final HashMap map = (HashMap)m_mapping.get( source ); 219 if( null == map ) 220 { 221 return null; 222 } 223 return (ConverterFactory)map.get( destination ); 224 } 225 }

This page was automatically generated by Maven