/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.isis.applib.services.exceprecog; import java.util.List; import javax.jdo.JDODataStoreException; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.base.Throwables; /** * An specific implementation of {@link ExceptionRecognizer} that looks for an * exception of the type provided in the constructor * and, if found anywhere in the {@link Throwables#getCausalChain(Throwable) causal chain}, * then returns a non-null message indicating that the exception has been recognized. * * <p> * If a messaging-parsing {@link Function} is provided through the constructor, * then the message can be altered. Otherwise the exception's {@link Throwable#getMessage() message} is returned as-is. */ public class ExceptionRecognizerForType extends ExceptionRecognizerAbstract { protected final static Predicate<Throwable> ofTypeExcluding(final Class<? extends Throwable> exceptionType, final String... messages) { return Predicates.and(ofType(exceptionType), excluding(messages)); } protected final static Predicate<Throwable> ofTypeIncluding(final Class<? extends Throwable> exceptionType, final String... messages) { return Predicates.and(ofType(exceptionType), including(messages)); } protected final static Predicate<Throwable> ofType(final Class<? extends Throwable> exceptionType) { return new Predicate<Throwable>() { @Override public boolean apply(Throwable input) { return exceptionType.isAssignableFrom(input.getClass()); } }; } /** * A {@link Predicate} that {@link Predicate#apply(Object) applies} only if the message(s) * supplied do <i>NOT</i> appear in the {@link Throwable} or any of its {@link Throwable#getCause() cause}s * (recursively). * * <p> * Intended to prevent too eager matching of an overly general exception type. */ protected final static Predicate<Throwable> excluding(final String... messages) { return new Predicate<Throwable>() { @Override public boolean apply(Throwable input) { final List<Throwable> causalChain = Throwables.getCausalChain(input); for (String message : messages) { for (Throwable throwable : causalChain) { final String throwableMessage = throwable.getMessage(); if(throwableMessage != null && throwableMessage.contains(message)) { return false; } if(throwable instanceof JDODataStoreException) { final JDODataStoreException jdoDataStoreException = (JDODataStoreException) throwable; final Throwable[] nestedExceptions = jdoDataStoreException.getNestedExceptions(); for (Throwable nestedException : nestedExceptions) { final String nestedThrowableMessage = nestedException.getMessage(); if(nestedThrowableMessage != null && nestedThrowableMessage.contains(message)) { return false; } } } } } return true; } }; } /** * A {@link Predicate} that {@link Predicate#apply(Object) applies} only if at least one of the message(s) * supplied <i>DO</i> appear in the {@link Throwable} or any of its {@link Throwable#getCause() cause}s * (recursively). * * <p> * Intended to prevent more precise matching of a specific general exception type. */ protected final static Predicate<Throwable> including(final String... messages) { return new Predicate<Throwable>() { @Override public boolean apply(Throwable input) { final List<Throwable> causalChain = Throwables.getCausalChain(input); for (String message : messages) { for (Throwable throwable : causalChain) { final String throwableMessage = throwable.getMessage(); if(throwableMessage != null && throwableMessage.contains(message)) { return true; } } } return false; } }; } public ExceptionRecognizerForType(Category category, final Class<? extends Exception> exceptionType, final Function<String,String> messageParser) { this(category, ofType(exceptionType), messageParser); } public ExceptionRecognizerForType(Category category, final Predicate<Throwable> predicate, final Function<String,String> messageParser) { super(category, predicate, messageParser); } public ExceptionRecognizerForType(Category category, Class<? extends Exception> exceptionType) { this(category, exceptionType, null); } public ExceptionRecognizerForType(final Class<? extends Exception> exceptionType, final Function<String,String> messageParser) { this(Category.OTHER, exceptionType, messageParser); } public ExceptionRecognizerForType(final Predicate<Throwable> predicate, final Function<String,String> messageParser) { this(Category.OTHER, predicate, messageParser); } public ExceptionRecognizerForType(Class<? extends Exception> exceptionType) { this(Category.OTHER, exceptionType); } }