/* * 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.deltaspike.core.impl.exception.control; import org.apache.deltaspike.core.api.exception.control.HandlerMethod; import org.apache.deltaspike.core.api.literal.AnyLiteral; import org.apache.deltaspike.core.util.HierarchyDiscovery; import javax.enterprise.inject.Typed; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Comparator; import java.util.Set; /** * Comparator to sort exception handlers according qualifier * ({@link org.apache.deltaspike.core.api.exception.control.BeforeHandles} first), ordinal * (highest to lowest) and finally hierarchy (least to most specific). */ @SuppressWarnings({ "MethodWithMoreThanThreeNegations" }) @Typed() public final class ExceptionHandlerComparator implements Comparator<HandlerMethod<?>> { /** * {@inheritDoc} */ @Override public int compare(HandlerMethod<?> lhs, HandlerMethod<?> rhs) { if (lhs.equals(rhs)) { return 0; } // Really this is so all handlers are returned in the TreeSet (even if they're of the same type, but one is // before, the other is not // Make sure both handlers are handling the same type, and also have the same qualifiers, if both of those are // true, then precedence comes into play if (lhs.getExceptionType().equals(rhs.getExceptionType()) && lhs.getQualifiers().equals(rhs.getQualifiers())) { final int precedenceReturnValue = comparePrecedence(lhs.getOrdinal(), rhs.getOrdinal(), lhs.isBeforeHandler()); // We really shouldn't be running into this case where everything is the same up until now, // but just in case, return both so both handlers are run. if (precedenceReturnValue == 0) { return -1; } // Precedence is different return precedenceReturnValue; } else { // Different qualifiers if (lhs.getExceptionType().equals(rhs.getExceptionType()) && !lhs.getQualifiers().equals(rhs.getQualifiers())) { if (lhs.getQualifiers().contains(new AnyLiteral())) { return -1; // Make sure @Any is first, as it's less specific } return 1; } return compareHierarchies(lhs.getExceptionType(), rhs.getExceptionType()); } // Currently we're only looking at one type of traversal mode, if this changes, we'll need // to re-add lines to check for this. } private int compareHierarchies(Type lhsExceptionType, Type rhsExceptionType) { HierarchyDiscovery lhsHierarchy = new HierarchyDiscovery(lhsExceptionType); Set<Type> lhsTypeclosure = lhsHierarchy.getTypeClosure(); if (lhsTypeclosure.contains(rhsExceptionType)) { final int indexOfLhsType = new ArrayList<Type>(lhsTypeclosure).indexOf(lhsExceptionType); final int indexOfRhsType = new ArrayList<Type>(lhsTypeclosure).indexOf(rhsExceptionType); if (indexOfLhsType > indexOfRhsType) { return 1; } } return -1; } private int comparePrecedence(final int lhs, final int rhs, final boolean isLhsBefore) { if (!isLhsBefore) { return (lhs - rhs); } else { return (lhs - rhs) * -1; } } }