Clover coverage report - Converter - 1.0
Coverage timestamp: Thu Jan 1 1970 10:00:00 EST
file stats: LOC: 226   Methods: 5
NCLOC: 131   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
AbstractMasterConverter.java 0% 0% 0% 0%
coverage
 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  0
     public Object convert( final Class destination,
 57   
                            final Object original,
 58   
                            final Object context )
 59   
         throws ConverterException
 60   
     {
 61  0
         final Class originalClass = original.getClass();
 62   
 
 63  0
         if( destination.isAssignableFrom( originalClass ) )
 64   
         {
 65  0
             return original;
 66   
         }
 67   
 
 68  0
         try
 69   
         {
 70   
             // Determine which converter to use
 71  0
             final Converter converter = findConverter( originalClass, destination );
 72   
 
 73   
             // Convert
 74  0
             final Object object = converter.convert( destination, original, context );
 75  0
             if( destination.isInstance( object ) )
 76   
             {
 77  0
                 return object;
 78   
             }
 79   
 
 80  0
             final String message =
 81   
                 REZ.format( "bad-return-type.error",
 82   
                             object.getClass().getName(),
 83   
                             destination.getName() );
 84  0
             throw new ConverterException( message );
 85   
         }
 86   
         catch( final Exception e )
 87   
         {
 88  0
             final String message =
 89   
                 REZ.format( "convert.error",
 90   
                             originalClass.getName(),
 91   
                             destination.getName() );
 92  0
             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  0
     private Converter findConverter( final Class originalClass,
 101   
                                      final Class destination )
 102   
         throws Exception
 103   
     {
 104   
         // Locate the factory to use
 105  0
         final ConverterFactory factory = findConverterFactory( originalClass, destination );
 106   
 
 107   
         // Create the converter
 108  0
         Converter converter = (Converter)m_converters.get( factory );
 109  0
         if( converter == null )
 110   
         {
 111  0
             converter = factory.createConverter();
 112  0
             m_converters.put( factory, converter );
 113   
         }
 114  0
         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  0
     protected void registerConverter( final ConverterFactory factory,
 125   
                                       final String source,
 126   
                                       final String destination )
 127   
     {
 128  0
         HashMap map = (HashMap)m_mapping.get( source );
 129  0
         if( null == map )
 130   
         {
 131  0
             map = new HashMap();
 132  0
             m_mapping.put( source, map );
 133   
         }
 134   
 
 135  0
         map.put( destination, factory );
 136   
 
 137   
         //Remove instance of converter if it has already been created
 138  0
         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  0
     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  0
         Class bestSrcMatch = null;
 156  0
         ConverterFactory matchFactory = null;
 157  0
         ArrayList queue = new ArrayList();
 158  0
         queue.add( originalClass );
 159   
 
 160  0
         while( !queue.isEmpty() )
 161   
         {
 162  0
             final Class clazz = (Class)queue.remove( 0 );
 163   
 
 164   
             // Add superclass and all interfaces
 165  0
             if( clazz.getSuperclass() != null )
 166   
             {
 167  0
                 queue.add( clazz.getSuperclass() );
 168   
             }
 169  0
             final Class[] interfaces = clazz.getInterfaces();
 170  0
             for( int i = 0; i < interfaces.length; i++ )
 171   
             {
 172  0
                 queue.add( interfaces[ i ] );
 173   
             }
 174   
 
 175   
             // Check if we can convert from current class to destination
 176  0
             final ConverterFactory factory =
 177   
                 getConverterFactory( clazz.getName(), destination.getName() );
 178  0
             if( factory == null )
 179   
             {
 180  0
                 continue;
 181   
             }
 182   
 
 183   
             // Choose the more specialised source class
 184  0
             if( bestSrcMatch == null || bestSrcMatch.isAssignableFrom( clazz ) )
 185   
             {
 186  0
                 bestSrcMatch = clazz;
 187  0
                 matchFactory = factory;
 188   
             }
 189  0
             else if( clazz.isAssignableFrom( bestSrcMatch ) )
 190   
             {
 191  0
                 continue;
 192   
             }
 193   
             else
 194   
             {
 195   
                 // Duplicate
 196  0
                 final String message = REZ.getString( "ambiguous-converter.error" );
 197  0
                 throw new ConverterException( message );
 198   
             }
 199   
         }
 200   
 
 201   
         // TODO - should cache the (src, dest) -> converter mapping
 202  0
         if( bestSrcMatch != null )
 203   
         {
 204  0
             return matchFactory;
 205   
         }
 206   
 
 207   
         // Could not find a converter
 208  0
         final String message = REZ.getString( "no-converter.error" );
 209  0
         throw new ConverterException( message );
 210   
     }
 211   
 
 212   
     /**
 213   
      * Retrieve factory for the converter that converts from source to destination.
 214   
      */
 215  0
     private ConverterFactory getConverterFactory( final String source,
 216   
                                                   final String destination )
 217   
     {
 218  0
         final HashMap map = (HashMap)m_mapping.get( source );
 219  0
         if( null == map )
 220   
         {
 221  0
             return null;
 222   
         }
 223  0
         return (ConverterFactory)map.get( destination );
 224   
     }
 225   
 }
 226