1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sourceforge.javadpkg.store;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.security.MessageDigest;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
32 import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
33 import org.apache.commons.compress.archivers.tar.TarConstants;
34
35 import net.sourceforge.javadpkg.DebianPackageConstants;
36 import net.sourceforge.javadpkg.io.DataConsumer;
37 import net.sourceforge.javadpkg.io.DataProducer;
38 import net.sourceforge.javadpkg.io.DataSource;
39 import net.sourceforge.javadpkg.io.FileMode;
40 import net.sourceforge.javadpkg.io.FileOwner;
41 import net.sourceforge.javadpkg.io.Streams;
42 import net.sourceforge.javadpkg.io.impl.DataDigestConsumer;
43 import net.sourceforge.javadpkg.io.impl.FileModeImpl;
44 import net.sourceforge.javadpkg.io.impl.FileOwnerImpl;
45
46
47
48
49
50
51
52
53
54 public class DataStoreNode implements DebianPackageConstants {
55
56
57
58 private DataSource source;
59
60 private String name;
61
62 private String target;
63
64 private FileOwner owner;
65
66 private FileMode mode;
67
68
69 private Map<String, DataStoreNode> childNodes;
70
71 private DataStoreNode parentNode;
72
73
74
75
76
77
78
79 public DataStoreNode() {
80 super();
81
82 this.source = null;
83 this.name = "";
84 this.target = null;
85 this.owner = new FileOwnerImpl(ROOT_GROUP_ID, ROOT_GROUP_NAME, ROOT_USER_ID, ROOT_USER_NAME);
86 this.mode = new FileModeImpl(DIRECTORY_MODE);
87 this.childNodes = new HashMap<>();
88 this.parentNode = null;
89 }
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106 public DataStoreNode(String name, FileOwner owner, FileMode mode) {
107 super();
108
109 if (name == null)
110 throw new IllegalArgumentException("Argument name is null.");
111 if (owner == null)
112 throw new IllegalArgumentException("Argument owner is null.");
113 if (mode == null)
114 throw new IllegalArgumentException("Argument mode is null.");
115
116 this.source = null;
117 this.name = name;
118 this.target = null;
119 this.owner = owner;
120 this.mode = mode;
121 this.childNodes = new HashMap<>();
122 this.parentNode = null;
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 public DataStoreNode(DataSource source, String name, FileOwner owner, FileMode mode) {
143
144 super();
145
146 if (source == null)
147 throw new IllegalArgumentException("Argument source is null.");
148 if (name == null)
149 throw new IllegalArgumentException("Argument name is null.");
150 if (owner == null)
151 throw new IllegalArgumentException("Argument owner is null.");
152 if (mode == null)
153 throw new IllegalArgumentException("Argument mode is null.");
154
155 this.source = source;
156 this.name = name;
157 this.target = null;
158 this.owner = owner;
159 this.mode = mode;
160 this.childNodes = null;
161 this.parentNode = null;
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 public DataStoreNode(String name, String target, FileOwner owner, FileMode mode) {
182 super();
183
184 if (name == null)
185 throw new IllegalArgumentException("Argument name is null.");
186 if (target == null)
187 throw new IllegalArgumentException("Argument target is null.");
188 if (owner == null)
189 throw new IllegalArgumentException("Argument owner is null.");
190 if (mode == null)
191 throw new IllegalArgumentException("Argument mode is null.");
192
193 this.source = null;
194 this.name = name;
195 this.target = target;
196 this.owner = owner;
197 this.mode = mode;
198 this.childNodes = null;
199 this.parentNode = null;
200 }
201
202
203
204
205
206
207
208
209
210 public String getName() {
211 return this.name;
212 }
213
214
215
216
217
218
219
220
221
222 public String getPath() {
223 StringBuilder sb;
224
225
226 sb = new StringBuilder();
227 this.addPath(sb);
228 return sb.toString();
229 }
230
231
232
233
234
235
236
237
238
239
240 private void addPath(StringBuilder builder) {
241 if (this.parentNode != null) {
242 this.parentNode.addPath(builder);
243 }
244 builder.append(this.name);
245 if (this.childNodes != null) {
246 builder.append('/');
247 }
248 }
249
250
251
252
253
254
255
256
257
258
259
260 public boolean isDirectory() {
261 return (this.childNodes != null);
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public boolean isFile() {
279 return ((this.source != null) || (this.target != null));
280 }
281
282
283
284
285
286
287
288
289
290
291
292 public boolean isSymbolicLink() {
293 return (this.target != null);
294 }
295
296
297
298
299
300
301
302
303
304
305
306 public long getSize() throws IOException {
307 long size = 0;
308
309
310
311 if (this.childNodes != null) {
312 if (!this.childNodes.isEmpty()) {
313 for (DataStoreNode node : this.childNodes.values()) {
314 size += node.getSize();
315 }
316 }
317 }
318
319 else if (this.target == null) {
320 size = this.source.getLength();
321 if (size < 0)
322 throw new IOException(
323 "Couldn't determine size for file |" + this.getPath() + "| (source |" + this.source.getName() + "|).");
324 }
325 return size;
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 public void addChildNode(DataStoreNode childNode) {
342 if (childNode == null)
343 throw new IllegalArgumentException("Argument childNode is null.");
344 if (!this.isDirectory())
345 throw new IllegalStateException("Can't add child node |" + childNode.getName() + "| because this node |"
346 + this.getPath() + "| is not a directory node.");
347 if (childNode.getParentNode() != null)
348 throw new IllegalStateException("Can't add child node |" + childNode.getName()
349 + "| because the child node is already added to parent node |" + childNode.getParentNode() + "|.");
350 if (this.childNodes.containsKey(childNode.getName()))
351 throw new IllegalStateException("Can't add child node |" + childNode.getName() + "| because this node |"
352 + this.getPath() + "| already contains a child node with that name.");
353
354 childNode.setParentNode(this);
355 this.childNodes.put(childNode.getName(), childNode);
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 public DataStoreNode getChildNodeByName(String name) {
373 if (name == null)
374 throw new IllegalArgumentException("Argument name is null.");
375 if (this.childNodes == null)
376 throw new IllegalArgumentException("Can't look for child node |" + name + "| because this node |" + this.getPath()
377 + "| is not a directory node.");
378
379 return this.childNodes.get(name);
380 }
381
382
383
384
385
386
387
388
389
390
391
392 private List<DataStoreNode> getChildNodes(boolean sorted) {
393 List<DataStoreNode> nodes;
394
395
396
397 nodes = new ArrayList<>(this.childNodes.values());
398
399
400 if (sorted) {
401 Collections.sort(nodes, new DataStoreNodeComparator());
402 }
403
404 return nodes;
405 }
406
407
408
409
410
411
412
413
414
415
416 private void setParentNode(DataStoreNode parentNode) {
417 this.parentNode = parentNode;
418 }
419
420
421
422
423
424
425
426
427
428
429 public DataStoreNode getParentNode() {
430 return this.parentNode;
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 public void write(TarArchiveOutputStream out) throws IOException {
447 String name;
448 TarArchiveEntry entry;
449
450
451 if (out == null)
452 throw new IllegalArgumentException("Argument out is null.");
453
454
455 name = "." + this.getPath();
456
457 if (this.target == null) {
458 entry = new TarArchiveEntry(name);
459 }
460
461 else {
462 entry = new TarArchiveEntry(name, TarConstants.LF_SYMLINK);
463 }
464 entry.setGroupId(this.owner.getGroupId());
465 entry.setGroupName(this.owner.getGroupName());
466 entry.setUserId(this.owner.getUserId());
467 entry.setUserName(this.owner.getUserName());
468 entry.setMode(this.mode.getMode());
469
470 if (this.source != null) {
471 entry.setSize(this.source.getLength());
472 }
473
474 if (this.target != null) {
475 entry.setLinkName(this.target);
476 }
477 out.putArchiveEntry(entry);
478
479
480 if (this.source != null) {
481 this.writeSource(out);
482 }
483 out.closeArchiveEntry();
484
485
486 if ((this.childNodes != null) && !this.childNodes.isEmpty()) {
487 this.writeNodes(out);
488 }
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502 private void writeSource(OutputStream out) throws IOException {
503
504 try {
505 try (InputStream in = this.source.getInputStream()) {
506 Streams.copy(in, out);
507 }
508 } catch (IOException e) {
509 throw new IOException("Couldn't write |" + this.getPath() + "| from source |" + this.source.getName()
510 + "| into the stream: " + e.getMessage());
511 }
512
513
514 if (this.source.isResettable()) {
515 this.source.reset();
516 }
517 }
518
519
520
521
522
523
524
525
526
527
528
529
530 private void writeNodes(TarArchiveOutputStream out) throws IOException {
531 List<DataStoreNode> nodes;
532
533
534
535 nodes = this.getChildNodes(true);
536
537
538 for (DataStoreNode node : nodes) {
539 node.write(out);
540 }
541 }
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560 public List<FileHash> createFileHashes(MessageDigest digest) throws IOException {
561 List<FileHash> hashes;
562 List<DataStoreNode> nodes;
563
564
565 if (digest == null)
566 throw new IllegalArgumentException("Argument md is null.");
567
568 hashes = new ArrayList<>();
569
570 if (this.source != null) {
571 hashes.add(this.createFileHash(digest));
572 }
573
574 else if ((this.childNodes != null) && !this.childNodes.isEmpty()) {
575 nodes = this.getChildNodes(true);
576 for (DataStoreNode node : nodes) {
577 hashes.addAll(node.createFileHashes(digest));
578 }
579 }
580
581 return hashes;
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596 private FileHash createFileHash(MessageDigest digest) throws IOException {
597 FileHash fileHash;
598 DataProducer producer;
599 DataConsumer consumer;
600 byte[] hash;
601 String path;
602
603
604
605 producer = Streams.createProducer(this.source);
606 consumer = new DataDigestConsumer(digest, "digest");
607 digest.reset();
608 Streams.transfer(producer, consumer);
609 hash = digest.digest();
610
611
612 if (this.source.isResettable()) {
613 this.source.reset();
614 }
615
616
617 path = this.getPath();
618 fileHash = new FileHashImpl(this.name, path, hash);
619 return fileHash;
620 }
621
622
623 }