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.inject.impl;
018
019 import java.lang.annotation.Annotation;
020 import java.util.ArrayList;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024
025 import org.apache.commons.inject.api.IBinding;
026 import org.apache.commons.inject.api.IKey;
027 import org.apache.commons.inject.api.Key;
028
029 /**
030 * A set of bindings, which are being collected to create, or implement
031 * an {@link IInjector}.
032 */
033
034 public class AbstractBindingSet {
035 /**
036 * The internal map of bindings uses this key.
037 */
038 public static class MappedKey<T> extends Key<T> {
039 private final Class<? extends Annotation> annotationType;
040 public MappedKey(Class<T> pType, String pName,
041 Annotation[] pAnnotations,
042 Class<? extends Annotation> pAnnotationType) {
043 super(pType, pName, pAnnotations);
044 annotationType = pAnnotationType;
045 }
046
047 public Class<? extends Annotation> getAnnotationType() {
048 return annotationType;
049 }
050 }
051 /**
052 * The internal map of bindings uses this value.
053 */
054 protected static class BindingAndKey<T> {
055 private IBinding<T> binding;
056 private final MappedKey<T> key;
057
058 BindingAndKey(IBinding<T> pBinding, MappedKey<T> pKey) {
059 binding = pBinding;
060 key = pKey;
061 }
062
063 public IBinding<T> getBinding() {
064 return binding;
065 }
066
067 public void setBinding(IBinding<T> pBinding) {
068 binding = pBinding;
069 }
070
071 public MappedKey<T> getKey() {
072 return key;
073 }
074 }
075 protected static class ReducedKey<T> {
076 private final Class<T> type;
077 private final String name;
078 ReducedKey(Class<T> pType, String pName) {
079 type = pType;
080 name = pName;
081 }
082 public Class<T> getType() {
083 return type;
084 }
085 public String getName() {
086 return name;
087 }
088 @Override
089 public int hashCode() {
090 return 31 * (31 + name.hashCode()) + type.hashCode();
091 }
092
093 @Override
094 public boolean equals(Object obj) {
095 if (this == obj)
096 return true;
097 if (obj == null)
098 return false;
099 if (getClass() != obj.getClass())
100 return false;
101 ReducedKey<?> other = (ReducedKey<?>) obj;
102 return getType() == other.getType() && getName().equals(other.getName());
103 }
104
105
106 }
107
108 protected final Map<ReducedKey<?>, List<BindingAndKey<?>>> map;
109
110 protected AbstractBindingSet(Map<ReducedKey<?>, List<BindingAndKey<?>>> pMap) {
111 map = pMap;
112 }
113
114 protected AbstractBindingSet() {
115 this(new HashMap<ReducedKey<?>, List<BindingAndKey<?>>>());
116 }
117
118
119 protected <T> ReducedKey<T> newReducedKey(IKey<T> pKey) {
120 return new ReducedKey<T>(pKey.getType(), pKey.getName());
121 }
122
123 protected List<BindingAndKey<?>> findOrCreateList(ReducedKey<?> pKey) {
124 List<BindingAndKey<?>> list = map.get(pKey);
125 if (list == null) {
126 list = new ArrayList<BindingAndKey<?>>();
127 map.put(pKey, list);
128 }
129 return list;
130 }
131
132 protected boolean isMatching(IKey<?> pSearchKey, MappedKey<?> pMapKey) {
133 // No need to compare type and name. They are matching, because
134 // we did a lookup with a ReducedKey to find the list of
135 // bindings and keys, from which pMapKey was taken.
136 if (!hasAnnotations(pMapKey.getAnnotations(), pSearchKey)
137 || !hasAnnotations(pSearchKey.getAnnotations(), pMapKey)) {
138 return false;
139 }
140 final Class<? extends Annotation> mappedAnnotationType = pMapKey.getAnnotationType();
141 if (mappedAnnotationType != null) {
142 boolean found = false;
143 for (Annotation searchAnnotation : pSearchKey.getAnnotations()) {
144 if (searchAnnotation != null && mappedAnnotationType == searchAnnotation.getClass()) {
145 found = true;
146 break;
147 }
148 }
149 if (!found) {
150 return false;
151 }
152
153 }
154 return true;
155 }
156
157 private boolean hasAnnotations(Annotation[] pAnnotations, IKey<?> pKey) {
158 for (Annotation annotation : pAnnotations) {
159 boolean found = false;
160 for (Annotation ann : pKey.getAnnotations()) {
161 if (annotation.equals(ann)) {
162 found = true;
163 break;
164 }
165 }
166 if (!found) {
167 return false;
168 }
169 }
170 return true;
171 }
172 }