001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.betwixt.strategy;
018
019 import java.util.ArrayList;
020 import java.util.Iterator;
021
022 /**
023 * <p>ClassNormalizer that uses a list of substitutions.</p>
024 * <p>
025 * This <code>ClassNormalizer</code> checks a list (in order) to find a matching
026 * Class.
027 * This match can be performed either strictly (using equality) or taking into account
028 * inheritance and implementation.
029 * If a match is found then the first substituted class is returned as the normalization.
030 * </p>
031 * @author Robert Burrell Donkin
032 * @since 0.5
033 */
034 public class ListedClassNormalizer extends ClassNormalizer {
035
036 /** Entries to be normalized */
037 private ArrayList normalizations = new ArrayList();
038 /** Should the equality (rather than isAssignabledFrom) be used to check */
039 private boolean strickCheck = false;
040
041 /**
042 * Is strict checking of substitutions on?
043 * @return true is equality is used to compare classes when considering substition,
044 * otherwise isAssignableFrom will be used so that super classes and super interfaces
045 * will be matched.
046 */
047 public boolean isStrickCheck() {
048 return strickCheck;
049 }
050
051 /**
052 * Sets strict checking of substitutions?
053 * @param strickCheck if true then equality will be used to compare classes
054 * when considering substition,
055 * otherwise isAssignableFrom will be used so that super classes and super interfaces
056 * will be matched.
057 */
058 public void setStrickCheck(boolean strickCheck) {
059 this.strickCheck = strickCheck;
060 }
061
062 /**
063 * Adds this given substitution to the list.
064 * No warning is given if the match has already been added to the list.
065 * @param match if any classes matching this then the normal class will be substituted
066 * @param substitute the normalized Class if the primary class is matched
067 */
068 public void addSubstitution( Class match, Class substitute ) {
069 normalizations.add( new ListEntry( match, substitute ));
070 }
071
072 /**
073 * Adds the given substitute to the list.
074 * This is a convenience method useful when {@link #isStrickCheck} is false.
075 * In this case, any subclasses (if this is a class) or implementating classes
076 * if this is an interface) will be subsituted with this value.
077 * @param substitute sustitude this Class
078 */
079 public void addSubstitution( Class substitute ) {
080 addSubstitution( substitute, substitute );
081 }
082
083 /**
084 * Normalize given class.
085 * The normalized Class is the Class that Betwixt should
086 * introspect.
087 * This strategy class allows the introspected Class to be
088 * varied.
089 *
090 * @param clazz the class to normalize, not null
091 * @return this implementation check it's list of substitutations in order
092 * and returns the first that matchs. If {@link #isStrickCheck} then equality
093 * is used otherwise isAssignableFrom is used (so that super class and interfaces are matched).
094 */
095 public Class normalize( Class clazz ) {
096 Iterator it = normalizations.iterator();
097 while ( it.hasNext() ) {
098 ListEntry entry = (ListEntry) it.next();
099 if ( strickCheck ) {
100 if ( entry.match.equals( clazz ) ) {
101 return entry.substitute;
102 }
103 } else {
104 if ( entry.match.isAssignableFrom( clazz )) {
105 return entry.substitute;
106 }
107 }
108 }
109
110 return clazz;
111 }
112
113 /** Holds list entries */
114 private class ListEntry {
115 /** Class to be check */
116 Class match;
117 /** Substituted to be returned */
118 Class substitute;
119
120 /**
121 * Base constructor
122 * @param match match this Class
123 * @param subsistute substitute matches with this Class
124 */
125 ListEntry( Class match, Class substitute ) {
126 this.match = match;
127 this.substitute = substitute;
128 }
129 }
130 }