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 static class PrototypeCloneFactory<T> implements Factory<T> {
50
51
52 private final T iPrototype;
53
54 private transient Method iCloneMethod;
55
56
57
58
59 private PrototypeCloneFactory(final T prototype, final Method method) {
60 iPrototype = prototype;
61 iCloneMethod = method;
62 }
63
64
65
66
67
68
69 @Override
70 @SuppressWarnings("unchecked")
71 public T create() {
72
73 if (iCloneMethod == null) {
74 findCloneMethod();
75 }
76
77 try {
78 return (T) iCloneMethod.invoke(iPrototype, (Object[]) null);
79 } catch (final IllegalAccessException ex) {
80 throw new FunctorException("PrototypeCloneFactory: Clone method must be public", ex);
81 } catch (final InvocationTargetException ex) {
82 throw new FunctorException("PrototypeCloneFactory: Clone method threw an exception", ex);
83 }
84 }
85
86
87
88
89 private void findCloneMethod() {
90 try {
91 iCloneMethod = iPrototype.getClass().getMethod("clone", (Class[]) null);
92 } catch (final NoSuchMethodException ex) {
93 throw new IllegalArgumentException("PrototypeCloneFactory: The clone method must exist and be public ");
94 }
95 }
96 }
97
98
99
100
101
102 static class PrototypeSerializationFactory<T extends Serializable> implements Factory<T> {
103
104
105 private final T iPrototype;
106
107
108
109
110 private PrototypeSerializationFactory(final T prototype) {
111 iPrototype = prototype;
112 }
113
114
115
116
117
118
119 @Override
120 @SuppressWarnings("unchecked")
121 public T create() {
122 final ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
123 ByteArrayInputStream bais = null;
124 try {
125 final ObjectOutputStream out = new ObjectOutputStream(baos);
126 out.writeObject(iPrototype);
127
128 bais = new ByteArrayInputStream(baos.toByteArray());
129 final ObjectInputStream in = new ObjectInputStream(bais);
130 return (T) in.readObject();
131
132 } catch (final ClassNotFoundException | IOException ex) {
133 throw new FunctorException(ex);
134 } finally {
135 try {
136 if (bais != null) {
137 bais.close();
138 }
139 } catch (final IOException ex) {
140
141 }
142 try {
143 baos.close();
144 } catch (final IOException ex) {
145
146 }
147 }
148 }
149 }
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 @SuppressWarnings("unchecked")
172 public static <T> Factory<T> prototypeFactory(final T prototype) {
173 if (prototype == null) {
174 return ConstantFactory.<T>constantFactory(null);
175 }
176 try {
177 final Method method = prototype.getClass().getMethod("clone", (Class[]) null);
178 return new PrototypeCloneFactory<>(prototype, method);
179
180 } catch (final NoSuchMethodException ex) {
181 try {
182 prototype.getClass().getConstructor(prototype.getClass());
183 return new InstantiateFactory<>(
184 (Class<T>) prototype.getClass(),
185 new Class<?>[] { prototype.getClass() },
186 new Object[] { prototype });
187 } catch (final NoSuchMethodException ex2) {
188 if (prototype instanceof Serializable) {
189 return (Factory<T>) new PrototypeSerializationFactory<>((Serializable) prototype);
190 }
191 }
192 }
193 throw new IllegalArgumentException("The prototype must be cloneable via a public clone method");
194 }
195
196
197
198
199 private PrototypeFactory() {
200 }
201
202 }