19
19
import java .io .ByteArrayOutputStream ;
20
20
import java .nio .charset .Charset ;
21
21
import java .nio .charset .StandardCharsets ;
22
+ import java .time .ZonedDateTime ;
23
+ import java .time .format .DateTimeParseException ;
22
24
23
25
import org .springframework .lang .Nullable ;
24
26
import org .springframework .util .Assert ;
25
27
import org .springframework .util .StringUtils ;
26
28
27
29
import static java .nio .charset .StandardCharsets .*;
30
+ import static java .time .format .DateTimeFormatter .*;
28
31
29
32
/**
30
33
* Represent the content disposition type and parameters as defined in RFC 2183.
@@ -45,16 +48,28 @@ public class ContentDisposition {
45
48
46
49
private final Long size ;
47
50
51
+ private final ZonedDateTime creationDate ;
52
+
53
+ private final ZonedDateTime modificationDate ;
54
+
55
+ private final ZonedDateTime readDate ;
56
+
48
57
49
58
/**
50
59
* Private constructor. See static factory methods in this class.
51
60
*/
52
- private ContentDisposition (@ Nullable String type , @ Nullable String name , @ Nullable String filename , @ Nullable Charset charset , @ Nullable Long size ) {
61
+ private ContentDisposition (@ Nullable String type , @ Nullable String name ,
62
+ @ Nullable String filename , @ Nullable Charset charset , @ Nullable Long size ,
63
+ @ Nullable ZonedDateTime creationDate , @ Nullable ZonedDateTime modificationDate , @ Nullable ZonedDateTime readDate ) {
64
+
53
65
this .type = type ;
54
66
this .name = name ;
55
67
this .filename = filename ;
56
68
this .charset = charset ;
57
69
this .size = size ;
70
+ this .creationDate = creationDate ;
71
+ this .modificationDate = modificationDate ;
72
+ this .readDate = readDate ;
58
73
}
59
74
60
75
@@ -100,6 +115,30 @@ public Long getSize() {
100
115
return this .size ;
101
116
}
102
117
118
+ /**
119
+ * Return the value of the {@literal creation-date} parameter, or {@code null} if not defined.
120
+ */
121
+ @ Nullable
122
+ public ZonedDateTime getCreationDate () {
123
+ return this .creationDate ;
124
+ }
125
+
126
+ /**
127
+ * Return the value of the {@literal modification-date} parameter, or {@code null} if not defined.
128
+ */
129
+ @ Nullable
130
+ public ZonedDateTime getModificationDate () {
131
+ return this .modificationDate ;
132
+ }
133
+
134
+ /**
135
+ * Return the value of the {@literal read-date} parameter, or {@code null} if not defined.
136
+ */
137
+ @ Nullable
138
+ public ZonedDateTime getReadDate () {
139
+ return this .readDate ;
140
+ }
141
+
103
142
104
143
/**
105
144
* Return a builder for a {@code ContentDisposition}.
@@ -115,11 +154,12 @@ public static Builder builder(String type) {
115
154
* Return an empty content disposition.
116
155
*/
117
156
public static ContentDisposition empty () {
118
- return new ContentDisposition (null , null , null , null , null );
157
+ return new ContentDisposition (null , null , null , null , null , null , null , null );
119
158
}
120
159
121
160
/**
122
161
* Parse a {@literal Content-Disposition} header value as defined in RFC 2183.
162
+ *
123
163
* @param contentDisposition the {@literal Content-Disposition} header value
124
164
* @return the parsed content disposition
125
165
* @see #toString()
@@ -132,6 +172,9 @@ public static ContentDisposition parse(String contentDisposition) {
132
172
String filename = null ;
133
173
Charset charset = null ;
134
174
Long size = null ;
175
+ ZonedDateTime creationDate = null ;
176
+ ZonedDateTime modificationDate = null ;
177
+ ZonedDateTime readDate = null ;
135
178
for (int i = 1 ; i < parts .length ; i ++) {
136
179
String part = parts [i ];
137
180
int eqIndex = part .indexOf ('=' );
@@ -155,12 +198,36 @@ else if (attribute.equals("filename") && (filename == null)) {
155
198
else if (attribute .equals ("size" ) ) {
156
199
size = Long .parseLong (value );
157
200
}
201
+ else if (attribute .equals ("creation-date" )) {
202
+ try {
203
+ creationDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
204
+ }
205
+ catch (DateTimeParseException ex ) {
206
+ // ignore
207
+ }
208
+ }
209
+ else if (attribute .equals ("modification-date" )) {
210
+ try {
211
+ modificationDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
212
+ }
213
+ catch (DateTimeParseException ex ) {
214
+ // ignore
215
+ }
216
+ }
217
+ else if (attribute .equals ("read-date" )) {
218
+ try {
219
+ readDate = ZonedDateTime .parse (value , RFC_1123_DATE_TIME );
220
+ }
221
+ catch (DateTimeParseException ex ) {
222
+ // ignore
223
+ }
224
+ }
158
225
}
159
226
else {
160
227
throw new IllegalArgumentException ("Invalid content disposition format" );
161
228
}
162
229
}
163
- return new ContentDisposition (type , name , filename , charset , size );
230
+ return new ContentDisposition (type , name , filename , charset , size , creationDate , modificationDate , readDate );
164
231
}
165
232
166
233
/**
@@ -229,7 +296,16 @@ public boolean equals(Object o) {
229
296
if (charset != null ? !charset .equals (that .charset ) : that .charset != null ) {
230
297
return false ;
231
298
}
232
- return size != null ? size .equals (that .size ) : that .size == null ;
299
+ if (size != null ? !size .equals (that .size ) : that .size != null ) {
300
+ return false ;
301
+ }
302
+ if (creationDate != null ? !creationDate .equals (that .creationDate ) : that .creationDate != null ) {
303
+ return false ;
304
+ }
305
+ if (modificationDate != null ? !modificationDate .equals (that .modificationDate ) : that .modificationDate != null ) {
306
+ return false ;
307
+ }
308
+ return readDate != null ? readDate .equals (that .readDate ) : that .readDate == null ;
233
309
}
234
310
235
311
@ Override
@@ -239,6 +315,9 @@ public int hashCode() {
239
315
result = 31 * result + (filename != null ? filename .hashCode () : 0 );
240
316
result = 31 * result + (charset != null ? charset .hashCode () : 0 );
241
317
result = 31 * result + (size != null ? size .hashCode () : 0 );
318
+ result = 31 * result + (creationDate != null ? creationDate .hashCode () : 0 );
319
+ result = 31 * result + (modificationDate != null ? modificationDate .hashCode () : 0 );
320
+ result = 31 * result + (readDate != null ? readDate .hashCode () : 0 );
242
321
return result ;
243
322
}
244
323
@@ -267,6 +346,21 @@ public String toString() {
267
346
builder .append ("; size=" );
268
347
builder .append (this .size );
269
348
}
349
+ if (this .creationDate != null ) {
350
+ builder .append ("; creation-date=\" " );
351
+ builder .append (RFC_1123_DATE_TIME .format (this .creationDate ));
352
+ builder .append ('\"' );
353
+ }
354
+ if (this .modificationDate != null ) {
355
+ builder .append ("; modification-date=\" " );
356
+ builder .append (RFC_1123_DATE_TIME .format (this .modificationDate ));
357
+ builder .append ('\"' );
358
+ }
359
+ if (this .readDate != null ) {
360
+ builder .append ("; read-date=\" " );
361
+ builder .append (RFC_1123_DATE_TIME .format (this .readDate ));
362
+ builder .append ('\"' );
363
+ }
270
364
return builder .toString ();
271
365
}
272
366
@@ -333,6 +427,21 @@ public interface Builder {
333
427
*/
334
428
Builder size (Long size );
335
429
430
+ /**
431
+ * Set the value of the {@literal creation-date} parameter.
432
+ */
433
+ Builder creationDate (ZonedDateTime creationDate );
434
+
435
+ /**
436
+ * Set the value of the {@literal modification-date} parameter.
437
+ */
438
+ Builder modificationDate (ZonedDateTime modificationDate );
439
+
440
+ /**
441
+ * Set the value of the {@literal read-date} parameter.
442
+ */
443
+ Builder readDate (ZonedDateTime readDate );
444
+
336
445
/**
337
446
* Build the content disposition
338
447
*/
@@ -352,6 +461,13 @@ private static class BuilderImpl implements Builder {
352
461
353
462
private Long size ;
354
463
464
+ private ZonedDateTime creationDate ;
465
+
466
+ private ZonedDateTime modificationDate ;
467
+
468
+ private ZonedDateTime readDate ;
469
+
470
+
355
471
public BuilderImpl (String type ) {
356
472
Assert .hasText (type , "'type' must not be not empty" );
357
473
this .type = type ;
@@ -382,9 +498,28 @@ public Builder size(Long size) {
382
498
return this ;
383
499
}
384
500
501
+ @ Override
502
+ public Builder creationDate (ZonedDateTime creationDate ) {
503
+ this .creationDate = creationDate ;
504
+ return this ;
505
+ }
506
+
507
+ @ Override
508
+ public Builder modificationDate (ZonedDateTime modificationDate ) {
509
+ this .modificationDate = modificationDate ;
510
+ return this ;
511
+ }
512
+
513
+ @ Override
514
+ public Builder readDate (ZonedDateTime readDate ) {
515
+ this .readDate = readDate ;
516
+ return this ;
517
+ }
518
+
385
519
@ Override
386
520
public ContentDisposition build () {
387
- return new ContentDisposition (this .type , this .name , this .filename , this .charset , this .size );
521
+ return new ContentDisposition (this .type , this .name , this .filename , this .charset ,
522
+ this .size , this .creationDate , this .modificationDate , this .readDate );
388
523
}
389
524
}
390
525
0 commit comments