Coverage Report - org.mule.config.ExceptionHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
ExceptionHelper
0%
0/222
0%
0/106
0
 
 1  
 /*
 2  
  * $Id: ExceptionHelper.java 20094 2010-11-05 20:14:34Z aperepel $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.config;
 12  
 
 13  
 import org.mule.api.MuleException;
 14  
 import org.mule.api.MuleRuntimeException;
 15  
 import org.mule.api.config.ExceptionReader;
 16  
 import org.mule.api.registry.ServiceType;
 17  
 import org.mule.config.i18n.CoreMessages;
 18  
 import org.mule.util.ClassUtils;
 19  
 import org.mule.util.MapUtils;
 20  
 import org.mule.util.SpiUtils;
 21  
 
 22  
 import java.io.IOException;
 23  
 import java.io.InputStream;
 24  
 import java.lang.reflect.InvocationTargetException;
 25  
 import java.util.ArrayList;
 26  
 import java.util.HashMap;
 27  
 import java.util.Iterator;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.Properties;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 
 35  
 /**
 36  
  * <code>ExceptionHelper</code> provides a number of helper functions that can be
 37  
  * useful for dealing with Mule exceptions. This class has 3 core functions - <p/> 1.
 38  
  * ErrorCode lookup. A corresponding Mule error code can be found using for a given
 39  
  * Mule exception 2. Additional Error information such as Java doc url for a given
 40  
  * exception can be resolved using this class 3. Error code mappings can be looked up
 41  
  * by providing the the protocol to map to and the Mule exception.
 42  
  */
 43  
 
 44  
 public final class ExceptionHelper
 45  
 {
 46  
     /**
 47  
      * This is the property to set the error code to no the message it is the
 48  
      * property name the Transport provider uses set the set the error code on the
 49  
      * underlying message
 50  
      */
 51  
     public static final String ERROR_CODE_PROPERTY = "error.code.property";
 52  
 
 53  
     /**
 54  
      * logger used by this class
 55  
      */
 56  0
     protected static final Log logger = LogFactory.getLog(ExceptionHelper.class);
 57  
 
 58  0
     private static String J2SE_VERSION = "";
 59  
 
 60  
     /**
 61  
      * todo How do you get the j2ee version??
 62  
      */
 63  
     private static final String J2EE_VERSION = "1.3ee";
 64  
 
 65  0
     private static Properties errorDocs = new Properties();
 66  0
     private static Properties errorCodes = new Properties();
 67  0
     private static Map reverseErrorCodes = null;
 68  0
     private static Map errorMappings = new HashMap();
 69  
 
 70  0
     private static int exceptionThreshold = 0;
 71  0
     private static boolean verbose = true;
 72  
 
 73  0
     private static boolean initialised = false;
 74  
 
 75  
     /**
 76  
      * A list of the exception readers to use for different types of exceptions
 77  
      */
 78  0
     private static List<ExceptionReader> exceptionReaders = new ArrayList<ExceptionReader>();
 79  
 
 80  
     /**
 81  
      * The default ExceptionReader which will be used for most types of exceptions
 82  
      */
 83  0
     private static ExceptionReader defaultExceptionReader = new DefaultExceptionReader();
 84  
 
 85  
     static
 86  
     {
 87  0
         initialise();
 88  0
     }
 89  
 
 90  
     /**
 91  
      * Do not instanciate.
 92  
      */
 93  
     private ExceptionHelper()
 94  0
     {
 95  
         // no-op
 96  0
     }
 97  
 
 98  
     private static void initialise()
 99  
     {
 100  
         try
 101  
         {
 102  0
             if (initialised)
 103  
             {
 104  0
                 return;
 105  
             }
 106  
 
 107  0
             registerExceptionReader(new MuleExceptionReader());
 108  0
             registerExceptionReader(new NamingExceptionReader());
 109  0
             J2SE_VERSION = System.getProperty("java.specification.version");
 110  
 
 111  0
             String name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath()
 112  
                     + "/mule-exception-codes.properties";
 113  0
             InputStream in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
 114  0
             if (in == null)
 115  
             {
 116  0
                 throw new IllegalArgumentException("Failed to load resource: " + name);
 117  
             }
 118  0
             errorCodes.load(in);
 119  0
             in.close();
 120  
 
 121  0
             reverseErrorCodes = MapUtils.invertMap(errorCodes);
 122  
 
 123  0
             name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath()
 124  
                     + "/mule-exception-config.properties";
 125  0
             in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
 126  0
             if (in == null)
 127  
             {
 128  0
                 throw new IllegalArgumentException("Failed to load resource: " + name);
 129  
             }
 130  0
             errorDocs.load(in);
 131  0
             in.close();
 132  
 
 133  0
             initialised = true;
 134  
         }
 135  0
         catch (Exception e)
 136  
         {
 137  0
             throw new MuleRuntimeException(CoreMessages.failedToLoad("Exception resources"), e);
 138  0
         }
 139  0
     }
 140  
 
 141  
     public static int getErrorCode(Class exception)
 142  
     {
 143  0
         String code = errorCodes.getProperty(exception.getName(), "-1");
 144  0
         return Integer.parseInt(code);
 145  
     }
 146  
 
 147  
     public static Class getErrorClass(int code)
 148  
     {
 149  0
         String key = String.valueOf(code);
 150  0
         Object clazz = reverseErrorCodes.get(key);
 151  0
         if (clazz == null)
 152  
         {
 153  0
             return null;
 154  
         }
 155  0
         else if (clazz instanceof Class)
 156  
         {
 157  0
             return (Class) clazz;
 158  
         }
 159  
         else
 160  
         {
 161  
             try
 162  
             {
 163  0
                 clazz = ClassUtils.loadClass(clazz.toString(), ExceptionHelper.class);
 164  
             }
 165  0
             catch (ClassNotFoundException e)
 166  
             {
 167  0
                 logger.error(e.getMessage(), e);
 168  0
                 return null;
 169  0
             }
 170  0
             reverseErrorCodes.put(key, clazz);
 171  0
             return (Class) clazz;
 172  
         }
 173  
     }
 174  
 
 175  
     private static Properties getErrorMappings(String protocol)
 176  
     {
 177  0
         Object m = errorMappings.get(protocol);
 178  0
         if (m != null)
 179  
         {
 180  0
             if (m instanceof Properties)
 181  
             {
 182  0
                 return (Properties) m;
 183  
             }
 184  
             else
 185  
             {
 186  0
                 return null;
 187  
             }
 188  
         }
 189  
         else
 190  
         {
 191  0
             String name = SpiUtils.SERVICE_ROOT + ServiceType.EXCEPTION.getPath() + "/" + protocol + "-exception-mappings.properties";
 192  0
             InputStream in = ExceptionHelper.class.getClassLoader().getResourceAsStream(name);
 193  0
             if (in == null)
 194  
             {
 195  0
                 errorMappings.put(protocol, "not found");
 196  0
                 if (logger.isDebugEnabled())
 197  
                 {
 198  0
                     logger.debug("Failed to load error mappings from: " + name
 199  
                             + " This may be because there are no error code mappings for protocol: "
 200  
                             + protocol);
 201  
                 }
 202  0
                 return null;
 203  
             }
 204  
 
 205  0
             Properties p = new Properties();
 206  
             try
 207  
             {
 208  0
                 p.load(in);
 209  0
                 in.close();
 210  
             }
 211  0
             catch (IOException iox)
 212  
             {
 213  0
                 throw new IllegalArgumentException("Failed to load resource: " + name);
 214  0
             }
 215  
 
 216  0
             errorMappings.put(protocol, p);
 217  0
             return p;
 218  
         }
 219  
     }
 220  
 
 221  
     public static String getErrorCodePropertyName(String protocol)
 222  
     {
 223  0
         protocol = protocol.toLowerCase();
 224  0
         Properties mappings = getErrorMappings(protocol);
 225  0
         if (mappings == null)
 226  
         {
 227  0
             return null;
 228  
         }
 229  0
         return mappings.getProperty(ERROR_CODE_PROPERTY);
 230  
     }
 231  
 
 232  
     public static String getErrorMapping(String protocol, Class exception)
 233  
     {
 234  0
         protocol = protocol.toLowerCase();
 235  0
         Properties mappings = getErrorMappings(protocol);
 236  0
         if (mappings == null)
 237  
         {
 238  0
             logger.info("No mappings found for protocol: " + protocol);
 239  0
             return String.valueOf(getErrorCode(exception));
 240  
         }
 241  
 
 242  0
         Class clazz = exception;
 243  0
         String code = null;
 244  0
         while (!clazz.equals(Object.class))
 245  
         {
 246  0
             code = mappings.getProperty(clazz.getName());
 247  0
             if (code == null)
 248  
             {
 249  0
                 clazz = clazz.getSuperclass();
 250  
             }
 251  
             else
 252  
             {
 253  0
                 return code;
 254  
             }
 255  
         }
 256  0
         code = String.valueOf(getErrorCode(exception));
 257  
         // Finally lookup mapping based on error code and return the Mule error
 258  
         // code if a match is not found
 259  0
         return mappings.getProperty(code, code);
 260  
     }
 261  
 
 262  
     public static String getJavaDocUrl(Class<?> exception)
 263  
     {
 264  0
         return getDocUrl("javadoc.", exception.getName());
 265  
     }
 266  
 
 267  
     public static String getDocUrl(Class<?> exception)
 268  
     {
 269  0
         return getDocUrl("doc.", exception.getName());
 270  
     }
 271  
 
 272  
     private static String getDocUrl(String prefix, String packageName)
 273  
     {
 274  0
         String key = prefix;
 275  0
         if (packageName.startsWith("java.") || packageName.startsWith("javax."))
 276  
         {
 277  0
             key += J2SE_VERSION;
 278  
         }
 279  0
         String url = getUrl(key, packageName);
 280  0
         if (url == null && (packageName.startsWith("java.") || packageName.startsWith("javax.")))
 281  
         {
 282  0
             key = prefix + J2EE_VERSION;
 283  0
             url = getUrl(key, packageName);
 284  
         }
 285  0
         if (url != null)
 286  
         {
 287  0
             if (!url.endsWith("/"))
 288  
             {
 289  0
                 url += "/";
 290  
             }
 291  0
             String s = packageName.replaceAll("[.]", "/");
 292  0
             s += ".html";
 293  0
             url += s;
 294  
         }
 295  0
         return url;
 296  
     }
 297  
 
 298  
     private static String getUrl(String key, String packageName)
 299  
     {
 300  0
         String url = null;
 301  0
         if (!key.endsWith("."))
 302  
         {
 303  0
             key += ".";
 304  
         }
 305  0
         while (packageName.length() > 0)
 306  
         {
 307  0
             url = errorDocs.getProperty(key + packageName, null);
 308  0
             if (url == null)
 309  
             {
 310  0
                 int i = packageName.lastIndexOf(".");
 311  0
                 if (i == -1)
 312  
                 {
 313  0
                     packageName = "";
 314  
                 }
 315  
                 else
 316  
                 {
 317  0
                     packageName = packageName.substring(0, i);
 318  
                 }
 319  0
             }
 320  
             else
 321  
             {
 322  
                 break;
 323  
             }
 324  
         }
 325  0
         return url;
 326  
     }
 327  
 
 328  
     public static Throwable getRootException(Throwable t)
 329  
     {
 330  0
         Throwable cause = t;
 331  0
         Throwable root = null;
 332  0
         while (cause != null)
 333  
         {
 334  0
             root = cause;
 335  0
             cause = getExceptionReader(cause).getCause(cause);
 336  
             // address some misbehaving exceptions, avoid endless loop
 337  0
             if (t == cause)
 338  
             {
 339  0
                 break;
 340  
             }
 341  
         }
 342  
 
 343  0
         return DefaultMuleConfiguration.fullStackTraces ? root : sanitize(root);
 344  
     }
 345  
 
 346  
     public static Throwable sanitizeIfNeeded(Throwable t)
 347  
     {
 348  0
         return DefaultMuleConfiguration.fullStackTraces ? t : sanitize(t);
 349  
     }
 350  
 
 351  
     /**
 352  
      * Removes some internal Mule entries from the stacktrace. Modifies the
 353  
      * passed-in throwable stacktrace.
 354  
      */
 355  
     public static Throwable sanitize(Throwable t)
 356  
     {
 357  0
         if (t == null)
 358  
         {
 359  0
             return null;
 360  
         }
 361  0
         StackTraceElement[] trace = t.getStackTrace();
 362  0
         List<StackTraceElement> newTrace = new ArrayList<StackTraceElement>();
 363  0
         for (StackTraceElement stackTraceElement : trace)
 364  
         {
 365  0
             if (!isMuleInternalClass(stackTraceElement.getClassName()))
 366  
             {
 367  0
                 newTrace.add(stackTraceElement);
 368  
             }
 369  
         }
 370  
 
 371  0
         StackTraceElement[] clean = new StackTraceElement[newTrace.size()];
 372  0
         newTrace.toArray(clean);
 373  0
         t.setStackTrace(clean);
 374  
 
 375  0
         Throwable cause = t.getCause();
 376  0
         while (cause != null)
 377  
         {
 378  0
             sanitize(cause);
 379  0
             cause = cause.getCause();
 380  
         }
 381  
 
 382  0
         return t;
 383  
     }
 384  
 
 385  
 
 386  
     /**
 387  
      * Removes some internal Mule entries from the stacktrace. Modifies the
 388  
      * passed-in throwable stacktrace.
 389  
      */
 390  
     public static Throwable summarise(Throwable t, int depth)
 391  
     {
 392  0
         t = sanitize(t);
 393  0
         StackTraceElement[] trace = t.getStackTrace();
 394  
 
 395  0
         int newStackDepth = Math.min(trace.length, depth);
 396  0
         StackTraceElement[] newTrace = new StackTraceElement[newStackDepth];
 397  
 
 398  0
         System.arraycopy(trace, 0, newTrace, 0, newStackDepth);
 399  0
         t.setStackTrace(newTrace);
 400  
         
 401  0
         return t;
 402  
     }
 403  
 
 404  
     private static boolean isMuleInternalClass(String className)
 405  
     {
 406  
         /*
 407  
            Sacrifice the code quality for the sake of keeping things simple -
 408  
            the alternative would be to pass MuleContext into every exception constructor.
 409  
         */
 410  0
         for (String mulePackage : DefaultMuleConfiguration.stackTraceFilter)
 411  
         {
 412  0
             if (className.startsWith(mulePackage))
 413  
             {
 414  0
                 return true;
 415  
             }
 416  
         }
 417  0
         return false;
 418  
     }
 419  
 
 420  
     public static Throwable getRootParentException(Throwable t)
 421  
     {
 422  0
         Throwable cause = t;
 423  0
         Throwable parent = t;
 424  0
         while (cause != null)
 425  
         {
 426  0
             if (cause.getCause() == null)
 427  
             {
 428  0
                 return parent;
 429  
             }
 430  0
             parent = cause;
 431  0
             cause = getExceptionReader(cause).getCause(cause);
 432  
             // address some misbehaving exceptions, avoid endless loop
 433  0
             if (t == cause)
 434  
             {
 435  0
                 break;
 436  
             }
 437  
         }
 438  0
         return t;
 439  
     }
 440  
 
 441  
     public static MuleException getRootMuleException(Throwable t)
 442  
     {
 443  0
         Throwable cause = t;
 444  0
         MuleException exception = null;
 445  0
         while (cause != null)
 446  
         {
 447  0
             if (cause instanceof MuleException)
 448  
             {
 449  0
                 exception = (MuleException) cause;
 450  
             }
 451  0
             final Throwable tempCause = getExceptionReader(cause).getCause(cause);
 452  0
             if (DefaultMuleConfiguration.fullStackTraces)
 453  
             {
 454  0
                 cause = tempCause;
 455  
             }
 456  
             else
 457  
             {
 458  0
                 cause = ExceptionHelper.sanitize(tempCause);
 459  
             }
 460  
             // address some misbehaving exceptions, avoid endless loop
 461  0
             if (t == cause)
 462  
             {
 463  0
                 break;
 464  
             }
 465  0
         }
 466  0
         return exception;
 467  
     }
 468  
 
 469  
     public static List getExceptionsAsList(Throwable t)
 470  
     {
 471  0
         List exceptions = new ArrayList();
 472  0
         Throwable cause = t;
 473  0
         while (cause != null)
 474  
         {
 475  0
             exceptions.add(0, cause);
 476  0
             cause = getExceptionReader(cause).getCause(cause);
 477  
             // address some misbehaving exceptions, avoid endless loop
 478  0
             if (t == cause)
 479  
             {
 480  0
                 break;
 481  
             }
 482  
         }
 483  0
         return exceptions;
 484  
     }
 485  
 
 486  
     public static Map getExceptionInfo(Throwable t)
 487  
     {
 488  0
         Map info = new HashMap();
 489  0
         Throwable cause = t;
 490  0
         while (cause != null)
 491  
         {
 492  0
             info.putAll(getExceptionReader(cause).getInfo(cause));
 493  0
             cause = getExceptionReader(cause).getCause(cause);
 494  
             // address some misbehaving exceptions, avoid endless loop
 495  0
             if (t == cause)
 496  
             {
 497  0
                 break;
 498  
             }
 499  
         }
 500  0
         return info;
 501  
     }
 502  
 
 503  
     public static String getExceptionStack(Throwable t)
 504  
     {
 505  0
         StringBuffer buf = new StringBuffer();
 506  
         // get exception stack
 507  0
         List exceptions = getExceptionsAsList(t);
 508  
 
 509  0
         int i = 1;
 510  0
         for (Iterator iterator = exceptions.iterator(); iterator.hasNext(); i++)
 511  
         {
 512  0
             if (i > exceptionThreshold && exceptionThreshold > 0)
 513  
             {
 514  0
                 buf.append("(").append(exceptions.size() - i + 1).append(" more...)");
 515  0
                 break;
 516  
             }
 517  0
             Throwable throwable = (Throwable) iterator.next();
 518  0
             ExceptionReader er = getExceptionReader(throwable);
 519  0
             buf.append(i).append(". ").append(er.getMessage(throwable)).append(" (");
 520  0
             buf.append(throwable.getClass().getName()).append(")\n");
 521  0
             if (verbose && throwable.getStackTrace().length > 0)
 522  
             {
 523  0
                 StackTraceElement e = throwable.getStackTrace()[0];
 524  0
                 buf.append("  ")
 525  
                         .append(e.getClassName())
 526  
                         .append(":")
 527  
                         .append(e.getLineNumber())
 528  
                         .append(" (")
 529  
                         .append(getJavaDocUrl(throwable.getClass()))
 530  
                         .append(")\n");
 531  
             }
 532  
         }
 533  0
         return buf.toString();
 534  
     }
 535  
 
 536  
     /**
 537  
      * Registers an exception reader with Mule
 538  
      *
 539  
      * @param reader the reader to register.
 540  
      */
 541  
     public static void registerExceptionReader(ExceptionReader reader)
 542  
     {
 543  0
         exceptionReaders.add(reader);
 544  0
     }
 545  
 
 546  
     /**
 547  
      * Gets an exception reader for the exception
 548  
      *
 549  
      * @param t the exception to get a reader for
 550  
      * @return either a specific reader or an instance of DefaultExceptionReader.
 551  
      *         This method never returns null;
 552  
      */
 553  
     public static ExceptionReader getExceptionReader(Throwable t)
 554  
     {
 555  0
         for (ExceptionReader exceptionReader : exceptionReaders)
 556  
         {
 557  0
             if (exceptionReader.getExceptionType().isInstance(t))
 558  
             {
 559  0
                 return exceptionReader;
 560  
             }
 561  
         }
 562  0
         return defaultExceptionReader;
 563  
     }
 564  
 
 565  
     public static String writeException(Throwable t)
 566  
     {
 567  0
         ExceptionReader er = getExceptionReader(t);
 568  0
         StringBuffer msg = new StringBuffer();
 569  0
         msg.append(er.getMessage(t)).append(". Type: ").append(t.getClass());
 570  0
         return msg.toString();
 571  
     }
 572  
 
 573  
     public static <T extends Throwable>T unwrap(T t)
 574  
     {
 575  0
         if(t instanceof InvocationTargetException)
 576  
         {
 577  0
             return (T)((InvocationTargetException)t).getTargetException();
 578  
         }
 579  0
         return t;
 580  
 
 581  
     }
 582  
 }