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 }