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.IOException;
20 import java.io.InputStream;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.OutputStream;
24 import java.io.Serializable;
25 import java.util.Arrays;
26
27 import org.apache.commons.io.IOUtils;
28 import org.apache.commons.io.output.ByteArrayOutputStream;
29 import org.apache.commons.lang3.ArrayUtils;
30 import org.apache.commons.lang3.ObjectUtils;
31 import org.apache.commons.lang3.Validate;
32 import org.apache.commons.lang3.builder.HashCodeBuilder;
33
34 import org.apache.commons.flatfile.util.ThresholdingInputStream;
35
36
37
38
39
40
41 public class DynamicField extends PadJustifyFieldSupport {
42
43
44
45 public static class Bounds implements Serializable {
46
47
48
49 public static final Bounds ALL_VALID = new Bounds() {
50 private static final long serialVersionUID = -2039931927562380883L;
51
52 {
53 this.minimum = 0;
54 this.maximum = Integer.MAX_VALUE;
55 }
56
57
58
59
60 public void setMinimum(int minimum) {
61 }
62
63
64
65
66 public void setMaximum(int maximum) {
67 }
68 };
69
70
71
72
73 public static final Bounds DEFAULT = ALL_VALID;
74
75 private static final long serialVersionUID = 1L;
76
77
78 protected int minimum;
79
80
81 protected int maximum;
82
83
84
85
86
87
88 public Bounds(int minimum, int maximum) {
89 setMinimum(minimum);
90 setMaximum(maximum);
91 }
92
93
94
95
96
97 private Bounds(Bounds example) {
98 this(example.getMinimum(), example.getMaximum());
99 }
100
101
102
103
104 private Bounds() {
105 }
106
107
108
109
110
111 public int getMaximum() {
112 return maximum;
113 }
114
115
116
117
118
119 public void setMaximum(int maximum) {
120 Validate.isTrue(maximum <= ALL_VALID.getMaximum(), "maximum value %d > %d", maximum,
121 ALL_VALID.getMaximum());
122 this.maximum = maximum;
123 }
124
125
126
127
128
129 public int getMinimum() {
130 return minimum;
131 }
132
133
134
135
136
137 public void setMinimum(int minimum) {
138 Validate.isTrue(minimum >= ALL_VALID.getMinimum(), "minimum value %s < %s", minimum,
139 ALL_VALID.getMinimum());
140 this.minimum = minimum;
141 }
142
143
144
145
146 public boolean equals(Object o) {
147 if (o == this) {
148 return true;
149 }
150 if (!(o instanceof Bounds)) {
151 return false;
152 }
153 Bounds ob = (Bounds) o;
154 return ob.getMaximum() == getMaximum() && ob.getMinimum() == getMinimum();
155 }
156
157
158
159
160 public int hashCode() {
161 return new HashCodeBuilder().append(minimum).append(maximum).toHashCode();
162 }
163
164
165
166
167
168
169 public void validate(byte[] value, DynamicField df) {
170 df.getUnderflow().check(value, getMinimum());
171 df.getOverflow().check(value, getMaximum());
172 }
173 }
174
175
176 private static final long serialVersionUID = -319053179741813727L;
177
178 private Bounds bounds;
179 private Overflow overflow;
180 private Underflow underflow;
181 private transient ByteArrayOutputStream buffer;
182
183
184
185
186 public DynamicField() {
187 this(new Bounds(Bounds.DEFAULT));
188 }
189
190
191
192
193
194 public DynamicField(Bounds bounds) {
195 setBounds(bounds);
196 }
197
198
199
200
201 public synchronized byte[] getValue() {
202 initialize(ArrayUtils.EMPTY_BYTE_ARRAY);
203 return buffer.toByteArray();
204 }
205
206
207
208
209 public int length() {
210 initialize(ArrayUtils.EMPTY_BYTE_ARRAY);
211 return buffer.size();
212 }
213
214
215
216
217
218
219
220
221
222 public synchronized void readFrom(InputStream is) throws IOException {
223 initialize();
224 buffer.reset();
225 IOUtils.copy(new ThresholdingInputStream(is, getBounds().getMaximum()), buffer);
226 }
227
228
229
230
231 public synchronized void setValue(byte[] b) {
232 getBounds().validate(b, this);
233 initialize();
234 iSetValue(b);
235 }
236
237
238
239
240 public synchronized void writeTo(OutputStream os) throws IOException {
241 initialize(ArrayUtils.EMPTY_BYTE_ARRAY);
242 buffer.writeTo(os);
243 }
244
245
246
247
248
249 public Overflow getOverflow() {
250 return overflow == null ? Overflow.ERROR : overflow;
251 }
252
253
254
255
256
257 public void setOverflow(Overflow overflow) {
258 this.overflow = overflow;
259 }
260
261
262
263
264
265 public Underflow getUnderflow() {
266 return underflow == null ? Underflow.ERROR : underflow;
267 }
268
269
270
271
272
273 public void setUnderflow(Underflow underflow) {
274 this.underflow = underflow;
275 }
276
277
278
279
280 public int hashCode() {
281 return new HashCodeBuilder().append(getBounds()).append(getValue()).toHashCode();
282 }
283
284
285
286
287 public boolean equals(Object other) {
288 if (other == this) {
289 return true;
290 }
291 if (!(other instanceof DynamicField)) {
292 return false;
293 }
294 DynamicField odf = (DynamicField) other;
295 return ObjectUtils.equals(odf.getBounds(), getBounds())
296 && Arrays.equals(odf.getValue(), getValue());
297 }
298
299
300
301
302 protected int getPadJustifyLength() {
303 return getBounds().getMinimum();
304 }
305
306
307
308
309
310 protected synchronized void iSetValue(byte[] value) {
311 super.setValue(value);
312 }
313
314
315
316
317 public DynamicField clone() {
318 DynamicField result = (DynamicField) super.clone();
319 result.setBounds(new Bounds(getBounds()));
320 result.buffer = null;
321 result.setValue(getValue());
322 return result;
323 }
324
325
326
327
328
329 public Bounds getBounds() {
330 return bounds;
331 }
332
333
334
335
336
337 public void setBounds(Bounds bounds) {
338 this.bounds = Validate.notNull(bounds, "bounds cannot be null");
339 }
340
341
342
343
344
345
346 private synchronized void writeObject(ObjectOutputStream out) throws IOException {
347 out.writeObject(getBounds());
348 initialize(ArrayUtils.EMPTY_BYTE_ARRAY);
349 out.write(buffer.size());
350 buffer.writeTo(out);
351 }
352
353
354
355
356
357
358
359 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
360 setBounds((Bounds) in.readObject());
361 int n = in.read();
362 initialize();
363 if (n > 0) {
364 IOUtils.copy(new ThresholdingInputStream(in, n), buffer);
365 }
366 }
367
368
369
370
371 private void initialize() {
372 initialize(null);
373 }
374
375
376
377
378
379 private synchronized void initialize(byte[] value) {
380 if (buffer == null) {
381 buffer = new ByteArrayOutputStream();
382 if (value != null) {
383 iSetValue(value);
384 }
385 }
386 }
387
388 }