001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.ioc.util;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newConcurrentMap;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newList;
019: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
020:
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.apache.tapestry.ioc.internal.util.InheritanceSearch;
025:
026: /**
027: * A key component in implementing the "Gang of Four" Strategy pattern. A StrategyRegistry will
028: * match up a given input type with a registered strategy for that type.
029: *
030: * @param <A>
031: * the type of the strategy adapter
032: */
033: public final class StrategyRegistry<A> {
034: private final Class<A> _adapterType;
035:
036: private final Map<Class, A> _registrations = newMap();
037:
038: private final Map<Class, A> _cache = newConcurrentMap();
039:
040: /**
041: * Creates a strategy registry for the given adapter type.
042: *
043: * @param adapterType
044: * the type of adapter retrieved from the registry
045: * @param registrations
046: * map of registrations (the contents of the map are copied)
047: */
048: public StrategyRegistry(final Class<A> adapterType,
049: Map<Class, A> registrations) {
050: _adapterType = adapterType;
051: _registrations.putAll(registrations);
052: }
053:
054: public static <A> StrategyRegistry<A> newInstance(
055: Class<A> adapterType, Map<Class, A> registrations) {
056: return new StrategyRegistry<A>(adapterType, registrations);
057: }
058:
059: public void clearCache() {
060: _cache.clear();
061: }
062:
063: public Class<A> getAdapterType() {
064: return _adapterType;
065: }
066:
067: /**
068: * Gets an adapter for an object. Searches based on the value's class, unless the value is null,
069: * in which case, a search on class void is used.
070: *
071: * @param value
072: * for which an adapter is needed
073: * @return the adaptoer for the value
074: * @throws IllegalArgumentException
075: * if no matching adapter may be found
076: */
077:
078: public A getByInstance(Object value) {
079: return get(value == null ? void.class : value.getClass());
080: }
081:
082: /**
083: * Searches for an adapter corresponding to the given input type.
084: *
085: * @param type
086: * the type to search
087: * @return the corresponding adapter
088: * @throws IllegalArgumentException
089: * if no matching adapter may be found
090: */
091: public A get(Class type) {
092: A result = _cache.get(type);
093:
094: if (result == null) {
095: result = findMatch(type);
096: _cache.put(type, result);
097: }
098:
099: return result;
100: }
101:
102: private A findMatch(Class type) {
103: for (Class t : new InheritanceSearch(type)) {
104: A result = _registrations.get(t);
105:
106: if (result != null)
107: return result;
108: }
109:
110: // Report the error. These things really confused the hell out of people in Tap4, so we're
111: // going the extra mile on the exception message.
112:
113: List<String> names = newList();
114: for (Class t : _registrations.keySet())
115: names.add(t.getName());
116:
117: throw new IllegalArgumentException(UtilMessages
118: .noStrategyAdapter(type, _adapterType, names));
119: }
120:
121: @Override
122: public String toString() {
123: return String.format("StrategyRegistry[%s]", _adapterType
124: .getName());
125: }
126: }
|