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 }