Coverage Report - org.mule.transformers.AbstractTransformer
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractTransformer
0%
0/111
0%
0/24
2.28
 
 1  
 /*
 2  
  * $Id: AbstractTransformer.java 7976 2007-08-21 14:26:13Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transformers;
 12  
 
 13  
 import org.mule.MuleManager;
 14  
 import org.mule.config.i18n.CoreMessages;
 15  
 import org.mule.providers.NullPayload;
 16  
 import org.mule.umo.UMOMessage;
 17  
 import org.mule.umo.endpoint.UMOImmutableEndpoint;
 18  
 import org.mule.umo.lifecycle.InitialisationException;
 19  
 import org.mule.umo.transformer.TransformerException;
 20  
 import org.mule.umo.transformer.UMOTransformer;
 21  
 import org.mule.util.BeanUtils;
 22  
 import org.mule.util.ClassUtils;
 23  
 import org.mule.util.StringMessageUtils;
 24  
 
 25  
 import java.util.List;
 26  
 
 27  
 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
 28  
 import org.apache.commons.logging.Log;
 29  
 import org.apache.commons.logging.LogFactory;
 30  
 
 31  
 /**
 32  
  * <code>AbstractTransformer</code> is a base class for all transformers.
 33  
  * Transformations transform one object into another.
 34  
  */
 35  
 
 36  
 public abstract class AbstractTransformer implements UMOTransformer
 37  
 {
 38  
     protected static final int DEFAULT_TRUNCATE_LENGTH = 200;
 39  
 
 40  
     /**
 41  
      * logger used by this class
 42  
      */
 43  0
     protected final Log logger = LogFactory.getLog(getClass());
 44  
 
 45  
     /**
 46  
      * The return type that will be returned by the {@link #transform} method is
 47  
      * called
 48  
      */
 49  0
     protected Class returnClass = null;
 50  
 
 51  
     /**
 52  
      * The name that identifies this transformer. If none is set the class name of
 53  
      * the transformer is used
 54  
      */
 55  0
     protected String name = null;
 56  
 
 57  
     /**
 58  
      * The endpoint that this transformer instance is configured on
 59  
      */
 60  0
     protected UMOImmutableEndpoint endpoint = null;
 61  
 
 62  
     /**
 63  
      * A list of supported Class types that the source payload passed into this
 64  
      * transformer
 65  
      */
 66  0
     protected final List sourceTypes = new CopyOnWriteArrayList();
 67  
 
 68  
     /**
 69  
      * This is the following transformer in the chain of transformers.
 70  
      */
 71  
     protected UMOTransformer nextTransformer;
 72  
 
 73  
     /**
 74  
      * Determines whether the transformer will throw an exception if the message
 75  
      * passed is is not supported or the return tye is incorrect
 76  
      */
 77  0
     private boolean ignoreBadInput = false;
 78  
 
 79  
     /**
 80  
      * default constructor required for discovery
 81  
      */
 82  
     public AbstractTransformer()
 83  0
     {
 84  0
         name = this.generateTransformerName();
 85  0
     }
 86  
 
 87  
     protected Object checkReturnClass(Object object) throws TransformerException
 88  
     {
 89  0
         if (returnClass != null)
 90  
         {
 91  0
             if (!returnClass.isInstance(object))
 92  
             {
 93  0
                 throw new TransformerException(
 94  
                     CoreMessages.transformUnexpectedType(object.getClass(), returnClass),
 95  
                     this);
 96  
             }
 97  
         }
 98  
 
 99  0
         if (logger.isDebugEnabled())
 100  
         {
 101  0
             logger.debug("The transformed object is of expected type. Type is: " +
 102  
                     ClassUtils.getSimpleName(object.getClass()));
 103  
         }
 104  
 
 105  0
         return object;
 106  
     }
 107  
 
 108  
     protected void registerSourceType(Class aClass)
 109  
     {
 110  0
         if (!sourceTypes.contains(aClass))
 111  
         {
 112  0
             sourceTypes.add(aClass);
 113  
 
 114  0
             if (aClass.equals(Object.class))
 115  
             {
 116  0
                 logger.debug("java.lang.Object has been added as source type for this transformer, there will be no source type checking performed");
 117  
             }
 118  
         }
 119  0
     }
 120  
 
 121  
     protected void unregisterSourceType(Class aClass)
 122  
     {
 123  0
         sourceTypes.remove(aClass);
 124  0
     }
 125  
 
 126  
     /**
 127  
      * @return transformer name
 128  
      */
 129  
     public String getName()
 130  
     {
 131  0
         return name;
 132  
     }
 133  
 
 134  
     /**
 135  
      * @param string
 136  
      */
 137  
     public void setName(String string)
 138  
     {
 139  0
         if (string == null)
 140  
         {
 141  0
             string = ClassUtils.getSimpleName(this.getClass());
 142  
         }
 143  
 
 144  0
         logger.debug("Setting transformer name to: " + string);
 145  0
         name = string;
 146  0
     }
 147  
 
 148  
     /*
 149  
      * (non-Javadoc)
 150  
      * 
 151  
      * @see org.mule.transformers.Transformer#getReturnClass()
 152  
      */
 153  
     public Class getReturnClass()
 154  
     {
 155  0
         return returnClass;
 156  
     }
 157  
 
 158  
     /*
 159  
      * (non-Javadoc)
 160  
      * 
 161  
      * @see org.mule.transformers.Transformer#setReturnClass(java.lang.String)
 162  
      */
 163  
     public void setReturnClass(Class newClass)
 164  
     {
 165  0
         returnClass = newClass;
 166  0
     }
 167  
 
 168  
     public boolean isSourceTypeSupported(Class aClass)
 169  
     {
 170  0
         return isSourceTypeSupported(aClass, false);
 171  
     }
 172  
 
 173  
     public boolean isSourceTypeSupported(Class aClass, boolean exactMatch)
 174  
     {
 175  0
         int numTypes = sourceTypes.size();
 176  
 
 177  0
         if (numTypes == 0)
 178  
         {
 179  0
             return !exactMatch;
 180  
         }
 181  
 
 182  0
         for (int i = 0; i < numTypes; i++)
 183  
         {
 184  0
             Class anotherClass = (Class) sourceTypes.get(i);
 185  0
             if (exactMatch)
 186  
             {
 187  0
                 if (anotherClass.equals(aClass))
 188  
                 {
 189  0
                     return true;
 190  
                 }
 191  
             }
 192  0
             else if (anotherClass.isAssignableFrom(aClass))
 193  
             {
 194  0
                 return true;
 195  
             }
 196  
         }
 197  
 
 198  0
         return false;
 199  
     }
 200  
 
 201  
     /**
 202  
      * Transforms the object.
 203  
      * 
 204  
      * @param src The source object to transform.
 205  
      * @return The transformed object
 206  
      */
 207  
     public final Object transform(Object src) throws TransformerException
 208  
     {
 209  0
         String encoding = null;
 210  
 
 211  0
         if (src instanceof UMOMessage && !isSourceTypeSupported(UMOMessage.class))
 212  
         {
 213  0
             encoding = ((UMOMessage) src).getEncoding();
 214  0
             src = ((UMOMessage) src).getPayload();
 215  
         }
 216  
 
 217  0
         if (encoding == null && endpoint != null)
 218  
         {
 219  0
             encoding = endpoint.getEncoding();
 220  
         }
 221  
 
 222  
         // last resort
 223  0
         if (encoding == null)
 224  
         {
 225  0
             encoding = MuleManager.getConfiguration().getEncoding();
 226  
         }
 227  
 
 228  0
         if (!isSourceTypeSupported(src.getClass()))
 229  
         {
 230  0
             if (ignoreBadInput)
 231  
             {
 232  0
                 logger.debug("Source type is incompatible with this transformer and property 'ignoreBadInput' is set to true, so the transformer chain will continue.");
 233  0
                 return nextTransform(src);
 234  
             }
 235  
             else
 236  
             {
 237  0
                 throw new TransformerException(
 238  
                     CoreMessages.transformOnObjectUnsupportedTypeOfEndpoint(this.getName(), 
 239  
                         src.getClass(), endpoint), this);
 240  
             }
 241  
         }
 242  
 
 243  0
         if (logger.isDebugEnabled())
 244  
         {
 245  0
             logger.debug("Applying transformer " + getName() + " (" + getClass().getName() + ")");
 246  0
             logger.debug("Object before transform: "
 247  
                             + StringMessageUtils.truncate(StringMessageUtils.toString(src), DEFAULT_TRUNCATE_LENGTH, false));
 248  
         }
 249  
 
 250  0
         Object result = doTransform(src, encoding);
 251  0
         if (result == null)
 252  
         {
 253  0
             result = NullPayload.getInstance();
 254  
         }
 255  
 
 256  0
         if (logger.isDebugEnabled())
 257  
         {
 258  0
             logger.debug("Object after transform: "
 259  
                             + StringMessageUtils.truncate(StringMessageUtils.toString(result), DEFAULT_TRUNCATE_LENGTH, false));
 260  
         }
 261  
 
 262  0
         result = checkReturnClass(result);
 263  
 
 264  0
         result = nextTransform(result);
 265  
 
 266  0
         return result;
 267  
     }
 268  
 
 269  
     public UMOImmutableEndpoint getEndpoint()
 270  
     {
 271  0
         return endpoint;
 272  
     }
 273  
 
 274  
     /*
 275  
      * (non-Javadoc)
 276  
      * 
 277  
      * @see org.mule.umo.transformer.UMOTransformer#setConnector(org.mule.umo.provider.UMOConnector)
 278  
      */
 279  
     public void setEndpoint(UMOImmutableEndpoint endpoint)
 280  
     {
 281  0
         this.endpoint = endpoint;
 282  0
         UMOTransformer trans = nextTransformer;
 283  0
         while (trans != null && endpoint != null)
 284  
         {
 285  0
             trans.setEndpoint(endpoint);
 286  0
             trans = trans.getNextTransformer();
 287  
         }
 288  0
     }
 289  
 
 290  
     protected abstract Object doTransform(Object src, String encoding) throws TransformerException;
 291  
 
 292  
     /*
 293  
      * (non-Javadoc)
 294  
      * 
 295  
      * @see org.mule.umo.transformer.UMOTransformer#getNextTransformer()
 296  
      */
 297  
     public UMOTransformer getNextTransformer()
 298  
     {
 299  0
         return nextTransformer;
 300  
     }
 301  
 
 302  
     /*
 303  
      * (non-Javadoc)
 304  
      * 
 305  
      * @see org.mule.umo.transformer.UMOTransformer#setNextTransformer(org.mule.umo.transformer.UMOTransformer)
 306  
      */
 307  
     public void setNextTransformer(UMOTransformer nextTransformer)
 308  
     {
 309  0
         this.nextTransformer = nextTransformer;
 310  0
     }
 311  
 
 312  
     /*
 313  
      * (non-Javadoc)
 314  
      * 
 315  
      * @see java.lang.Object#clone()
 316  
      */
 317  
     public Object clone() throws CloneNotSupportedException
 318  
     {
 319  
         try
 320  
         {
 321  
             /*
 322  
              * Object.clone() is horribly broken, so we create a new instance
 323  
              * manually and let BeanUtils populate all accessible "properties". That
 324  
              * is about the best we can do to fulfill the general clone() contract
 325  
              * (providing a mostly-correct shallow copy out of the box) even though
 326  
              * it is obviously wrong in the face of objects with nontrivial "getter"
 327  
              * methods. It would be much, much better to enforce the use of
 328  
              * copy-constructors, or even better to just *not copy at all*.
 329  
              * UMOTransformer.clone() will apparently go away in 2.0 in favor of
 330  
              * BeanFactory-created instances so there is still hope, though I am
 331  
              * sceptical whether his will fix all aliasing problems. It seems that
 332  
              * the reference cycle between transformers and endpoints and the dynamic
 333  
              * updating of copied transformers with new endpoints is the real root of
 334  
              * the problem.
 335  
              */
 336  0
             AbstractTransformer clone = (AbstractTransformer)BeanUtils.cloneBean(this);
 337  
 
 338  
             /*
 339  
              * clear out the cloned list of types since subclass constructors
 340  
              * probably have registered their source types, leading to duplicates..
 341  
              */
 342  0
             clone.sourceTypes.clear();
 343  0
             clone.sourceTypes.addAll(sourceTypes);
 344  
 
 345  
             // recursively copy any chained transformers
 346  0
             if (nextTransformer != null)
 347  
             {
 348  0
                 clone.setNextTransformer((UMOTransformer) nextTransformer.clone());
 349  
             }
 350  
 
 351  
             // update all chained transformers to use this endpoint which is *shared*
 352  0
             clone.setEndpoint(endpoint);
 353  
 
 354  0
             return clone;
 355  
         }
 356  0
         catch (Exception e)
 357  
         {
 358  0
             throw (CloneNotSupportedException) new CloneNotSupportedException("Failed to clone transformer: "
 359  
                             + e.getMessage()).initCause(e);
 360  
         }
 361  
     }
 362  
 
 363  
     /**
 364  
      * Will return the return type for the last transformer in the chain
 365  
      * 
 366  
      * @return the last transformers return type
 367  
      */
 368  
     public Class getFinalReturnClass()
 369  
     {
 370  0
         UMOTransformer tempTrans = this;
 371  0
         UMOTransformer returnTrans = this;
 372  0
         while (tempTrans != null)
 373  
         {
 374  0
             returnTrans = tempTrans;
 375  0
             tempTrans = tempTrans.getNextTransformer();
 376  
         }
 377  0
         return returnTrans.getReturnClass();
 378  
     }
 379  
 
 380  
     /**
 381  
      * Template method were deriving classes can do any initialisation after the
 382  
      * properties have been set on this transformer
 383  
      * 
 384  
      * @throws InitialisationException
 385  
      */
 386  
     public void initialise() throws InitialisationException
 387  
     {
 388  
         // nothing to do
 389  0
     }
 390  
 
 391  
     protected String generateTransformerName()
 392  
     {
 393  0
         return ClassUtils.getSimpleName(this.getClass());
 394  
     }
 395  
 
 396  
     public boolean isIgnoreBadInput()
 397  
     {
 398  0
         return ignoreBadInput;
 399  
     }
 400  
 
 401  
     public void setIgnoreBadInput(boolean ignoreBadInput)
 402  
     {
 403  0
         this.ignoreBadInput = ignoreBadInput;
 404  0
     }
 405  
 
 406  
     // @Override
 407  
     public String toString()
 408  
     {
 409  0
         StringBuffer sb = new StringBuffer(80);
 410  0
         sb.append(ClassUtils.getSimpleName(this.getClass()));
 411  0
         sb.append("{this=").append(Integer.toHexString(System.identityHashCode(this)));
 412  0
         sb.append(", name='").append(name).append('\'');
 413  0
         sb.append(", ignoreBadInput=").append(ignoreBadInput);
 414  0
         sb.append(", returnClass=").append(returnClass);
 415  0
         sb.append(", sourceTypes=").append(sourceTypes);
 416  0
         sb.append('}');
 417  0
         return sb.toString();                        
 418  
     }
 419  
 
 420  
     public boolean isAcceptNull()
 421  
     {
 422  0
         return false;
 423  
     }
 424  
 
 425  
     /**
 426  
      * Safely call the next transformer in chain, if any.
 427  
      */
 428  
     protected Object nextTransform(Object result)
 429  
             throws TransformerException
 430  
     {
 431  0
         if (nextTransformer != null)
 432  
         {
 433  0
             logger.debug("Following transformer in the chain is " + nextTransformer.getName() + " ("
 434  
                             + nextTransformer.getClass().getName() + ")");
 435  0
             result = nextTransformer.transform(result);
 436  
         }
 437  0
         return result;
 438  
     }
 439  
 }