1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.collections4.functors;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.Serializable;
25 import java.lang.reflect.InvocationTargetException;
26 import java.lang.reflect.Method;
27
28 import org.apache.commons.collections4.Factory;
29 import org.apache.commons.collections4.FunctorException;
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class PrototypeFactory {
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65 @SuppressWarnings("unchecked")
66 public static <T> Factory<T> prototypeFactory(final T prototype) {
67 if (prototype == null) {
68 return ConstantFactory.<T>constantFactory(null);
69 }
70 try {
71 final Method method = prototype.getClass().getMethod("clone", (Class[]) null);
72 return new PrototypeCloneFactory<>(prototype, method);
73
74 } catch (final NoSuchMethodException ex) {
75 try {
76 prototype.getClass().getConstructor(new Class<?>[] { prototype.getClass() });
77 return new InstantiateFactory<>(
78 (Class<T>) prototype.getClass(),
79 new Class<?>[] { prototype.getClass() },
80 new Object[] { prototype });
81 } catch (final NoSuchMethodException ex2) {
82 if (prototype instanceof Serializable) {
83 return (Factory<T>) new PrototypeSerializationFactory<>((Serializable) prototype);
84 }
85 }
86 }
87 throw new IllegalArgumentException("The prototype must be cloneable via a public clone method");
88 }
89
90
91
92
93 private PrototypeFactory() {
94 super();
95 }
96
97
98
99
100
101
102 static class PrototypeCloneFactory<T> implements Factory<T> {
103
104
105 private final T iPrototype;
106
107 private transient Method iCloneMethod;
108
109
110
111
112 private PrototypeCloneFactory(final T prototype, final Method method) {
113 super();
114 iPrototype = prototype;
115 iCloneMethod = method;
116 }
117
118
119
120
121 private void findCloneMethod() {
122 try {
123 iCloneMethod = iPrototype.getClass().getMethod("clone", (Class[]) null);
124 } catch (final NoSuchMethodException ex) {
125 throw new IllegalArgumentException("PrototypeCloneFactory: The clone method must exist and be public ");
126 }
127 }
128
129
130
131
132
133
134 @Override
135 @SuppressWarnings("unchecked")
136 public T create() {
137
138 if (iCloneMethod == null) {
139 findCloneMethod();
140 }
141
142 try {
143 return (T) iCloneMethod.invoke(iPrototype, (Object[]) null);
144 } catch (final IllegalAccessException ex) {
145 throw new FunctorException("PrototypeCloneFactory: Clone method must be public", ex);
146 } catch (final InvocationTargetException ex) {
147 throw new FunctorException("PrototypeCloneFactory: Clone method threw an exception", ex);
148 }
149 }
150 }
151
152
153
154
155
156
157 static class PrototypeSerializationFactory<T extends Serializable> implements Factory<T> {
158
159
160 private final T iPrototype;
161
162
163
164
165 private PrototypeSerializationFactory(final T prototype) {
166 super();
167 iPrototype = prototype;
168 }
169
170
171
172
173
174
175 @Override
176 @SuppressWarnings("unchecked")
177 public T create() {
178 final ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
179 ByteArrayInputStream bais = null;
180 try {
181 final ObjectOutputStream out = new ObjectOutputStream(baos);
182 out.writeObject(iPrototype);
183
184 bais = new ByteArrayInputStream(baos.toByteArray());
185 final ObjectInputStream in = new ObjectInputStream(bais);
186 return (T) in.readObject();
187
188 } catch (final ClassNotFoundException ex) {
189 throw new FunctorException(ex);
190 } catch (final IOException ex) {
191 throw new FunctorException(ex);
192 } finally {
193 try {
194 if (bais != null) {
195 bais.close();
196 }
197 } catch (final IOException ex) {
198
199 }
200 try {
201 baos.close();
202 } catch (final IOException ex) {
203
204 }
205 }
206 }
207 }
208
209 }