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 javax.imageio.spi.ServiceRegistry;
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 = ServiceRegistry
52 .lookupProviders(Caster.class);
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 public static <F extends OctaveObject,
78 T extends OctaveObject> T cast(final Class<T> toClass,
79 final F from) {
80 if (from == null) {
81 return null;
82 }
83 if (toClass.isInstance(from)) {
84 return toClass.cast(from);
85 }
86 final ClassPair<F, T> cp = new ClassPair<F, T>(unsafeGetClass(from),
87 toClass);
88 final Caster<F, T> caster = casterMapGet(cp);
89 if (caster == null) {
90 throw new OctaveClassCastException(null, from, toClass);
91 }
92 return caster.cast(from);
93 }
94
95 @SuppressWarnings("unchecked")
96 private static <F> Class<F> unsafeGetClass(final F from) {
97 return (Class<F>) from.getClass();
98 }
99
100 @SuppressWarnings("unchecked")
101 private static <F extends OctaveObject,
102 T extends OctaveObject>
103 Caster<F, T> casterMapGet(final ClassPair<F, T> cp) {
104 initIfNecessary();
105 if (!casterMap.containsKey(cp)) {
106 return null;
107 }
108 final Caster<F, T> caster = (Caster<F, T>) casterMap.get(cp);
109 if (!caster.from().equals(cp.from)) {
110 throw new OctaveCastServiceException
111 ("!caster.from().equals(cp.from)");
112 }
113 if (!caster.to().equals(cp.to)) {
114 throw new OctaveCastServiceException("!caster.to().equals(cp.to)");
115 }
116 return caster;
117 }
118
119
120
121
122
123
124
125
126 private static class ClassPair<F, T> {
127 ClassPair(final Class<F> from, final Class<T> to) {
128 this.from = from;
129 this.to = to;
130 }
131
132 private final Class<F> from;
133
134 private final Class<T> to;
135
136 @Override
137 public int hashCode() {
138 int result = 1;
139 result = PRIME * result + ((from == null) ? 0 : from.hashCode());
140 result = PRIME * result + ((to == null) ? 0 : to.hashCode());
141 return result;
142 }
143
144 @Override
145 public boolean equals(final Object obj) {
146 if (this == obj) {
147 return true;
148 }
149 if (obj == null) {
150 return false;
151 }
152 if (getClass() != obj.getClass()) {
153 return false;
154 }
155 final ClassPair<?, ?> other = (ClassPair<?, ?>) obj;
156 if (from == null) {
157 if (other.from != null) {
158 return false;
159 }
160 } else if (!from.equals(other.from)) {
161 return false;
162 }
163 if (to == null) {
164 if (other.to != null) {
165 return false;
166 }
167 } else if (!to.equals(other.to)) {
168 return false;
169 }
170 return true;
171 }
172 }
173
174 }