1 /*
2  * Copyright 2011 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.modelmapper.internal;
17
18 import java.util.Map;
19 import java.util.concurrent.ConcurrentHashMap;
20
21 import org.modelmapper.config.Configuration;
22
23 /**
24  * Statically stores and retrieves TypeInfo instances by type, parent type, and configuration.
25  * 
26  * @author Jonathan Halterman
27  */

28 class TypeInfoRegistry {
29   private static final Map<TypeInfoKey, TypeInfoImpl<?>> cache = new ConcurrentHashMap<TypeInfoKey, TypeInfoImpl<?>>();
30
31   private static class TypeInfoKey {
32     private final Class<?> type;
33     private final Configuration configuration;
34
35     TypeInfoKey(Class<?> type, Configuration configuration) {
36       this.type = type;
37       this.configuration = configuration;
38     }
39
40     @Override
41     public boolean equals(Object o) {
42       if (o == this)
43         return true;
44       if (!(o instanceof TypeInfoKey))
45         return false;
46       TypeInfoKey other = (TypeInfoKey) o;
47       return type.equals(other.type) && configuration.equals(other.configuration);
48     }
49
50     @Override
51     public int hashCode() {
52       int result = 31 * type.hashCode();
53       return 31 * result + configuration.hashCode();
54     }
55   }
56
57   @SuppressWarnings("unchecked")
58   static <T> TypeInfoImpl<T> typeInfoFor(Accessor accessor, InheritingConfiguration configuration) {
59     return TypeInfoRegistry.typeInfoFor(null, (Class<T>) accessor.getType(), configuration);
60   }
61
62   /**
63    * Returns a non-cached TypeInfoImpl instance if there is no supported ValueAccessReader for the
64    * {@code sourceType}, else a cached TypeInfoImpl instance is returned.
65    */

66   static <T> TypeInfoImpl<T> typeInfoFor(T source, Class<T> sourceType,
67       InheritingConfiguration configuration) {
68     if (configuration.valueAccessStore.getFirstSupportedReader(sourceType) != null && source != null)
69       return new TypeInfoImpl<T>(source, sourceType, configuration);
70     return typeInfoFor(sourceType, configuration);
71   }
72
73   /**
74    * Returns a statically cached TypeInfoImpl instance for the given criteria.
75    */

76   @SuppressWarnings("unchecked")
77   static <T> TypeInfoImpl<T> typeInfoFor(Class<T> sourceType, InheritingConfiguration configuration) {
78     TypeInfoKey pair = new TypeInfoKey(sourceType, configuration);
79     TypeInfoImpl<T> typeInfo = (TypeInfoImpl<T>) cache.get(pair);
80
81     if (typeInfo == null) {
82       synchronized (cache) {
83         typeInfo = (TypeInfoImpl<T>) cache.get(pair);
84         if (typeInfo == null) {
85           typeInfo = new TypeInfoImpl<T>(null, sourceType, configuration);
86           cache.put(pair, typeInfo);
87         }
88       }
89     }
90
91     return typeInfo;
92   }
93 }
94