1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.flatfile;
18
19 import java.io.InputStream;
20 import java.lang.reflect.InvocationHandler;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Proxy;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.WeakHashMap;
27
28 import org.apache.commons.lang3.ClassUtils;
29
30
31
32
33
34 public class ImmutableEntity {
35 private static class ImmutableEntityInvocationHandler implements InvocationHandler {
36
37 private static final String[] ALLOWED_VOID = { "readFrom", "writeTo" };
38 private static final String CLONE = "clone";
39 private static final String EQUALS = "equals";
40 private static final String READ_FROM = "readFrom";
41 private static final String GET_CHILD = "getChild";
42 private static final String GET_VALUE = "getValue";
43 private static final String IS_SIZABLE = "isSizable";
44 private static final byte[] READ_BUFFER = new byte[1024];
45 private static final int BUF_LEN = READ_BUFFER.length;
46
47 private Entity delegate;
48
49
50
51
52
53 private ImmutableEntityInvocationHandler(Entity delegate) {
54 this.delegate = delegate;
55 }
56
57
58
59
60
61 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
62 String name = method.getName();
63
64
65
66 if (method.getReturnType() == Void.TYPE && Arrays.binarySearch(ALLOWED_VOID, name) < 0) {
67 return null;
68 }
69 if (READ_FROM.equals(name)) {
70 InputStream is = (InputStream) args[0];
71 int remaining = delegate.length();
72 while (remaining > 0) {
73 int toread = remaining > BUF_LEN ? BUF_LEN : remaining;
74 int read = is.read(READ_BUFFER, 0, toread);
75 if (read < 0) {
76 break;
77 }
78 remaining -= read;
79 }
80 return null;
81 }
82 if (CLONE.equals(name)) {
83
84
85 return proxy;
86 }
87 if (EQUALS.equals(name)) {
88 return Boolean.valueOf(proxy == args[0]);
89 }
90 if (IS_SIZABLE.equals(name)) {
91 return Boolean.FALSE;
92 }
93 Object result = method.invoke(delegate, args);
94 if (GET_CHILD.equals(name)) {
95 result = of((Entity) result);
96 }
97
98
99 if (GET_VALUE.equals(name)) {
100 byte[] test = (byte[]) method.invoke(delegate, args);
101 if (result == test) {
102 result = new byte[test.length];
103 System.arraycopy(test, 0, (byte[]) result, 0, test.length);
104 }
105 }
106 return result;
107 }
108 }
109
110 private static final Map<Entity, Entity> PROXIES = new WeakHashMap<Entity, Entity>();
111
112
113
114
115 private ImmutableEntity() {
116 }
117
118
119
120
121
122
123 public static Entity of(Entity e) {
124 Entity result = PROXIES.get(e);
125 if (result == null) {
126 result = (Entity) Proxy.newProxyInstance(e.getClass().getClassLoader(),
127 getInterfaces(e), new ImmutableEntityInvocationHandler(e));
128 PROXIES.put(e, result);
129 }
130 return result;
131 }
132
133
134
135
136
137
138 private static Class<?>[] getInterfaces(Object o) {
139 final List<Class<?>> interfaces = ClassUtils.getAllInterfaces(o.getClass());
140 return interfaces.toArray(new Class[interfaces.size()]);
141 }
142 }