// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server;

import com.google.gerrit.exceptions.StorageException;
import com.google.gerrit.git.LockFailureException;
import com.google.gerrit.server.update.UpdateException;
import java.util.Optional;
import org.eclipse.jgit.lib.RefUpdate;

/**
 * Class to detect and handle exceptions that are caused by temporary errors, and hence should cause
 * a retry of the failed operation.
 */
public class ExceptionHookImpl implements ExceptionHook {
  @Override
  public boolean shouldRetry(Throwable throwable) {
    return isLockFailure(throwable);
  }

  @Override
  public Optional<String> formatCause(Throwable throwable) {
    if (isLockFailure(throwable)) {
      return Optional.of(RefUpdate.Result.LOCK_FAILURE.name());
    }
    return Optional.empty();
  }

  private static boolean isLockFailure(Throwable throwable) {
    if (throwable instanceof UpdateException || throwable instanceof StorageException) {
      throwable = throwable.getCause();
    }
    return throwable instanceof LockFailureException;
  }
}

@@ -659,93 +659,71 @@
 gle.
-gerrit.exceptions.StorageException;%0Aimport com.google.gerrit.git.LockFailureException
+common.base.Predicate;%0Aimport com.google.common.base.Throwables
 ;%0Aim
@@ -749,27 +749,22 @@
 rit.
-server.update.Updat
+git.LockFailur
 eExc
@@ -1426,19 +1426,33 @@
 ) %7B%0A    
-if 
+return isMatching
 (throwab
@@ -1445,32 +1445,40 @@
 tching(throwable
+, t -%3E t
  instanceof Upda
@@ -1477,83 +1477,403 @@
 eof 
-UpdateException %7C%7C throwable instanceof StorageException) %7B%0A      t
+LockFailureException);%0A  %7D%0A%0A  /**%0A   * Check whether the given exception or any of its causes matches the given predicate.%0A   *%0A   * @param throwable Exception that should be tested%0A   * @param predicate predicate to check if a throwable matches%0A   * @return %7B@code true%7D if the given exception or any of its causes matches the given predicate%0A   */%0A  private static boolean isMatching(T
 hrowable
  = t
@@ -1872,10 +1872,8 @@
 able
- =
  thr
@@ -1882,26 +1882,43 @@
 able
-.getCause();%0A    %7D
+, Predicate%3CThrowable%3E predicate) %7B
 %0A   
@@ -1925,25 +1925,25 @@
  return 
-t
+T
 hrowable
  instanc
@@ -1938,40 +1938,64 @@
 able
- instanceof LockFailureException
+s.getCausalChain(throwable).stream().anyMatch(predicate)
 ;%0A  

Improve detection of LockFailureException