/*
* JBoss, Home of Professional Open Source
* Copyright 2011, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* 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 org.jboss.solder.exception.control;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Set;
import org.jboss.solder.reflection.HierarchyDiscovery;
import org.jboss.solder.exception.control.HandlerMethod;
import org.jboss.solder.exception.control.TraversalMode;
/**
* Comparator to sort exception handlers according qualifier ({@link TraversalMode#DEPTH_FIRST} first), precedence
* (highest to lowest) and finally hierarchy (least to most specific).
*/
@SuppressWarnings({"MethodWithMoreThanThreeNegations"})
public final class ExceptionHandlerComparator implements Comparator<HandlerMethod<?>> {
/**
* {@inheritDoc}
*/
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
// inbound, the other is outbound
if (lhs.getExceptionType().equals(rhs.getExceptionType())) {
final int returnValue = this.comparePrecedence(lhs.getPrecedence(), rhs.getPrecedence(),
lhs.getTraversalMode() == TraversalMode.DEPTH_FIRST);
// Compare number of qualifiers if they exist so handlers that handle the same type
// are both are returned and not thrown out (order doesn't really matter)
if (returnValue == 0 && !lhs.getQualifiers().isEmpty()) {
return -1;
}
// Either precedence is non-zero or lhs doesn't have qualifiers so return the precedence compare
// If it's 0 this is essentially the same handler for our purposes
return returnValue;
} else {
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 isAsc) {
if (isAsc) {
return (lhs - rhs);
} else {
return (lhs - rhs) * -1;
}
}
}