@Override
    public Type determine(final BackgroundException failure) {
        if(log.isDebugEnabled()) {
            log.debug(String.format("Determine cause for failure %s", failure));
        }
        for(Throwable cause : ExceptionUtils.getThrowableList(failure)) {
            if(failure instanceof UnsupportedException) {
                return Type.unsupported;
            }
            if(failure instanceof LoginFailureException) {
                return Type.login;
            }
            if(cause instanceof ResolveFailedException) {
                return Type.network;
            }
            if(failure instanceof TransferCanceledException) {
                return Type.skip;
            }
            if(failure instanceof ConnectionCanceledException) {
                return Type.cancel;
            }
            if(cause instanceof ConnectionTimeoutException) {
                return Type.network;
            }
            if(cause instanceof ConnectionRefusedException) {
                return Type.network;
            }
            if(cause instanceof SSLNegotiateException) {
                return Type.application;
            }
            if(cause instanceof SSLHandshakeException) {
                return Type.application;
            }
            if(cause instanceof SSLException) {
                return Type.network;
            }
            if(cause instanceof NoHttpResponseException) {
                return Type.network;
            }
            if(cause instanceof ConnectTimeoutException) {
                return Type.network;
            }
            if(cause instanceof SocketException
                    || cause instanceof IOResumeException
                    || cause instanceof TimeoutException // Used in Promise#retrieve
                    || cause instanceof SocketTimeoutException
                    || cause instanceof UnknownHostException) {
                return Type.network;
            }
            if(cause instanceof QuotaException) {
                return Type.quota;
            }
            if(cause instanceof AntiVirusAccessDeniedException) {
                return Type.antivirus;
            }
        }
        return Type.application;
    }
@Test
    public void testDetermine() {
        assertEquals(FailureDiagnostics.Type.application, new DefaultFailureDiagnostics().determine(null));
        assertEquals(FailureDiagnostics.Type.network, new DefaultFailureDiagnostics().determine(new ResolveFailedException("d", null)));
        assertEquals(FailureDiagnostics.Type.cancel, new DefaultFailureDiagnostics().determine(new ResolveCanceledException()));
        assertEquals(FailureDiagnostics.Type.login, new DefaultFailureDiagnostics().determine(new LoginFailureException("d")));
        assertEquals(FailureDiagnostics.Type.cancel, new DefaultFailureDiagnostics().determine(new ConnectionCanceledException()));
        // By user
        assertEquals(FailureDiagnostics.Type.skip, new DefaultFailureDiagnostics().determine(new TransferCanceledException()));
        assertEquals(FailureDiagnostics.Type.application, new DefaultFailureDiagnostics().determine(new BackgroundException(new ConnectionCanceledException())));
        // By transfer status
        assertEquals(FailureDiagnostics.Type.cancel, new DefaultFailureDiagnostics().determine(new TransferStatusCanceledException()));
    }