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    }