1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package eu.simuline.octave.type.cast;
17
18 import java.util.HashMap;
19 import java.util.Iterator;
20 import java.util.Map;
21
22 import java.util.ServiceLoader;
23
24 import eu.simuline.octave.exception.OctaveClassCastException;
25 import eu.simuline.octave.exception.OctaveCastServiceException;
26 import eu.simuline.octave.type.OctaveObject;
27
28
29
30
31
32
33 public final class Cast {
34
35 private static final int PRIME = 31;
36
37
38
39
40 private static Map<ClassPair<?, ?>, Caster<?, ?>> casterMap;
41
42 private Cast() {
43 throw new UnsupportedOperationException("Do not instantiate");
44 }
45
46 @SuppressWarnings("unchecked")
47 private static synchronized void initIfNecessary() {
48 if (casterMap == null) {
49 casterMap = new HashMap<ClassPair<?, ?>, Caster<?, ?>>();
50 @SuppressWarnings("rawtypes")
51 final Iterator<Caster> sp =
52 ServiceLoader.load(Caster.class).iterator();
53 while (sp.hasNext()) {
54 register(sp.next());
55 }
56 }
57 }
58
59 private static <F, T> void register(final Caster<F, T> caster) {
60 final ClassPair<F, T> cp = new ClassPair<F, T>(caster.from(),
61 caster.to());
62 Caster<?, ?> overwritten = casterMap.put(cp, caster);
63 if (overwritten != null) {
64 throw new OctaveCastServiceException("casterMap.containsKey(cp)");
65 }
66 }
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public static <F extends OctaveObject,
84 T extends OctaveObject> T cast(final Class<T> toClass,
85 final F from) {
86 if (from == null) {
87 return null;
88 }
89 if (toClass.isInstance(from)) {
90 return toClass.cast(from);
91 }
92 final ClassPair<F, T> cp = new ClassPair<F, T>(unsafeGetClass(from),
93 toClass);
94 final Caster<F, T> caster = casterMapGet(cp);
95 if (caster == null) {
96 throw new OctaveClassCastException(null, from, toClass);
97 }
98 return caster.cast(from);
99 }
100
101 @SuppressWarnings("unchecked")
102 private static <F> Class<F> unsafeGetClass(final F from) {
103 return (Class<F>) from.getClass();
104 }
105
106 @SuppressWarnings("unchecked")
107 private static <F extends OctaveObject,
108 T extends OctaveObject>
109 Caster<F, T> casterMapGet(final ClassPair<F, T> cp) {
110 initIfNecessary();
111 if (!casterMap.containsKey(cp)) {
112 return null;
113 }
114 final Caster<F, T> caster = (Caster<F, T>) casterMap.get(cp);
115 if (!caster.from().equals(cp.from)) {
116 throw new OctaveCastServiceException
117 ("!caster.from().equals(cp.from)");
118 }
119 if (!caster.to().equals(cp.to)) {
120 throw new OctaveCastServiceException("!caster.to().equals(cp.to)");
121 }
122 return caster;
123 }
124
125
126
127
128
129
130
131
132 private static class ClassPair<F, T> {
133 ClassPair(final Class<F> from, final Class<T> to) {
134 this.from = from;
135 this.to = to;
136 }
137
138 private final Class<F> from;
139
140 private final Class<T> to;
141
142 @Override
143 public int hashCode() {
144 int result = 1;
145 result = PRIME * result + ((from == null) ? 0 : from.hashCode());
146 result = PRIME * result + ((to == null) ? 0 : to.hashCode());
147 return result;
148 }
149
150 @Override
151 public boolean equals(final Object obj) {
152 if (this == obj) {
153 return true;
154 }
155 if (obj == null) {
156 return false;
157 }
158 if (getClass() != obj.getClass()) {
159 return false;
160 }
161 final ClassPair<?, ?> other = (ClassPair<?, ?>) obj;
162 if (from == null) {
163 if (other.from != null) {
164 return false;
165 }
166 } else if (!from.equals(other.from)) {
167 return false;
168 }
169 if (to == null) {
170 if (other.to != null) {
171 return false;
172 }
173 } else if (!to.equals(other.to)) {
174 return false;
175 }
176 return true;
177 }
178 }
179
180 }