|
3 | 3 | import dev.vml.es.acm.core.util.*; |
4 | 4 | import java.io.*; |
5 | 5 | import java.nio.charset.StandardCharsets; |
6 | | -import java.nio.file.Files; |
7 | 6 | import java.util.*; |
8 | 7 | import java.util.concurrent.Executors; |
9 | 8 | import java.util.function.Consumer; |
10 | 9 | import java.util.function.Function; |
11 | 10 | import java.util.stream.Stream; |
12 | 11 | import javax.jcr.Node; |
| 12 | +import javax.jcr.NodeIterator; |
13 | 13 | import javax.jcr.Property; |
14 | 14 | import javax.jcr.RepositoryException; |
15 | 15 | import org.apache.commons.io.IOUtils; |
|
35 | 35 | */ |
36 | 36 | public class RepoResource { |
37 | 37 |
|
| 38 | + public static final String FILE_MIME_TYPE_DEFAULT = "application/octet-stream"; |
| 39 | + |
38 | 40 | private final Repo repo; |
39 | 41 |
|
40 | 42 | private final String path; |
@@ -402,6 +404,50 @@ public RepoResource moveInPlace(RepoResource target, boolean replace) { |
402 | 404 | return target; |
403 | 405 | } |
404 | 406 |
|
| 407 | + // AEM 6.5.0 has no 'resourceResolver.orderBefore' so adding own based on: |
| 408 | + // https://github.com/apache/sling-org-apache-sling-jcr-resource/commit/3b8f01d226124417bdfdba4ca2086114a73a7c5d |
| 409 | + public boolean orderBefore(String siblingName) { |
| 410 | + Node parentNode = parent().requireNode(); |
| 411 | + String name = getName(); |
| 412 | + try { |
| 413 | + long existingNodePosition = -1; |
| 414 | + long siblingNodePosition = -1; |
| 415 | + long index = 0; |
| 416 | + |
| 417 | + NodeIterator nodeIterator = parentNode.getNodes(); |
| 418 | + while (nodeIterator.hasNext()) { |
| 419 | + Node childNode = nodeIterator.nextNode(); |
| 420 | + String childName = childNode.getName(); |
| 421 | + |
| 422 | + if (childName.equals(name)) { |
| 423 | + existingNodePosition = index; |
| 424 | + } |
| 425 | + if (siblingName != null && childName.equals(siblingName)) { |
| 426 | + siblingNodePosition = index; |
| 427 | + } else if (siblingName == null && childName.equals(name)) { |
| 428 | + if (existingNodePosition == nodeIterator.getSize() - 1) { |
| 429 | + return false; |
| 430 | + } |
| 431 | + } |
| 432 | + index++; |
| 433 | + } |
| 434 | + |
| 435 | + if (siblingName != null |
| 436 | + && existingNodePosition >= 0 |
| 437 | + && siblingNodePosition >= 0 |
| 438 | + && existingNodePosition == siblingNodePosition - 1) { |
| 439 | + return false; |
| 440 | + } |
| 441 | + |
| 442 | + parentNode.orderBefore(name, siblingName); |
| 443 | + repo.commit(String.format("reordering resource '%s' before '%s'", path, siblingName)); |
| 444 | + repo.getLogger().info("Reordered resource '{}' before '{}'", path, siblingName); |
| 445 | + return true; |
| 446 | + } catch (RepositoryException e) { |
| 447 | + throw new RepoException(String.format("Cannot reorder resource '%s' before '%s'", path, siblingName), e); |
| 448 | + } |
| 449 | + } |
| 450 | + |
405 | 451 | public RepoResource parent() { |
406 | 452 | String parentPath = parentPath(); |
407 | 453 | if (parentPath == null) { |
@@ -534,100 +580,92 @@ public RepoResourceState state() { |
534 | 580 | return new RepoResourceState(path, true, resource.getValueMap()); |
535 | 581 | } |
536 | 582 |
|
537 | | - public RepoResource saveFile(String mimeType, Consumer<OutputStream> dataWriter) { |
538 | | - saveFileInternal(mimeType, null, dataWriter); |
539 | | - return this; |
| 583 | + public RepoResource saveFile(InputStream data) { |
| 584 | + return saveFile(FILE_MIME_TYPE_DEFAULT, data); |
540 | 585 | } |
541 | 586 |
|
542 | | - public RepoResource saveFile(String mimeType, File file) { |
543 | | - saveFile(mimeType, (OutputStream os) -> { |
544 | | - try (InputStream is = Files.newInputStream(file.toPath())) { |
545 | | - IOUtils.copy(is, os); |
546 | | - } catch (IOException e) { |
547 | | - throw new RepoException(String.format("Cannot write file '%s' to path '%s'!", file.getPath(), path), e); |
548 | | - } |
549 | | - }); |
| 587 | + public RepoResource saveFile(String mimeType, InputStream data) { |
| 588 | + return saveFile(Collections.singletonMap(JcrConstants.JCR_MIMETYPE, mimeType), data); |
| 589 | + } |
| 590 | + |
| 591 | + public RepoResource saveFile(Map<String, Object> properties, InputStream data) { |
| 592 | + saveFileInternal(properties, data, null); |
550 | 593 | return this; |
551 | 594 | } |
552 | 595 |
|
553 | | - public RepoResource saveFile(String mimeType, Object data) { |
554 | | - saveFileInternal(mimeType, data, null); |
| 596 | + public RepoResource saveFile(Consumer<OutputStream> dataWriter) { |
| 597 | + return saveFile(FILE_MIME_TYPE_DEFAULT, dataWriter); |
| 598 | + } |
| 599 | + |
| 600 | + public RepoResource saveFile(String mimeType, Consumer<OutputStream> dataWriter) { |
| 601 | + return saveFile(Collections.singletonMap(JcrConstants.JCR_MIMETYPE, mimeType), dataWriter); |
| 602 | + } |
| 603 | + |
| 604 | + public RepoResource saveFile(Map<String, Object> properties, Consumer<OutputStream> dataWriter) { |
| 605 | + saveFileInternal(properties, null, dataWriter); |
555 | 606 | return this; |
556 | 607 | } |
557 | 608 |
|
558 | | - private void saveFileInternal(String mimeType, Object data, Consumer<OutputStream> dataWriter) { |
| 609 | + private void saveFileInternal(Map<String, Object> properties, InputStream data, Consumer<OutputStream> dataWriter) { |
| 610 | + if (properties == null) { |
| 611 | + properties = new HashMap<>(); |
| 612 | + } |
| 613 | + if (!properties.containsKey(JcrConstants.JCR_MIMETYPE)) { |
| 614 | + Map<String, Object> propertiesMutable = new HashMap<>(properties); |
| 615 | + propertiesMutable.put(JcrConstants.JCR_MIMETYPE, FILE_MIME_TYPE_DEFAULT); |
| 616 | + properties = propertiesMutable; |
| 617 | + } |
| 618 | + |
559 | 619 | Resource mainResource = resolve(); |
560 | 620 | try { |
561 | | - if (mainResource == null) { |
562 | | - String parentPath = StringUtils.substringBeforeLast(path, "/"); |
563 | | - Resource parent = repo.getResourceResolver().getResource(parentPath); |
564 | | - if (parent == null) { |
565 | | - throw new RepoException( |
566 | | - String.format("Cannot save file as parent path '%s' does not exist!", parentPath)); |
567 | | - } |
568 | | - String name = StringUtils.substringAfterLast(path, "/"); |
569 | | - Map<String, Object> mainValues = new HashMap<>(); |
570 | | - mainValues.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FILE); |
571 | | - mainResource = repo.getResourceResolver().create(parent, name, mainValues); |
| 621 | + if (mainResource != null) { |
| 622 | + repo.getResourceResolver().delete(mainResource); |
| 623 | + } |
572 | 624 |
|
573 | | - Map<String, Object> contentValues = new HashMap<>(); |
574 | | - setFileContent(contentValues, mimeType, data, dataWriter); |
575 | | - repo.getResourceResolver().create(mainResource, JcrConstants.JCR_CONTENT, contentValues); |
| 625 | + Resource parent = parent().resolve(); |
| 626 | + if (parent == null) { |
| 627 | + throw new RepoException( |
| 628 | + String.format("Cannot save file as parent path '%s' does not exist!", parentPath())); |
| 629 | + } |
| 630 | + String name = getName(); |
| 631 | + Map<String, Object> mainValues = new HashMap<>(); |
| 632 | + mainValues.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_FILE); |
| 633 | + mainResource = repo.getResourceResolver().create(parent, name, mainValues); |
576 | 634 |
|
577 | | - repo.commit(String.format("creating file at path '%s'", path)); |
578 | | - repo.getLogger().info("Created file at path '{}'", path); |
579 | | - } else { |
580 | | - Resource contentResource = mainResource.getChild(JcrConstants.JCR_CONTENT); |
581 | | - if (contentResource == null) { |
582 | | - Map<String, Object> contentValues = new HashMap<>(); |
583 | | - setFileContent(contentValues, mimeType, data, dataWriter); |
584 | | - repo.getResourceResolver().create(mainResource, JcrConstants.JCR_CONTENT, contentValues); |
585 | | - } else { |
586 | | - ModifiableValueMap contentValues = |
587 | | - Objects.requireNonNull(contentResource.adaptTo(ModifiableValueMap.class)); |
588 | | - setFileContent(contentValues, mimeType, data, dataWriter); |
589 | | - } |
| 635 | + Map<String, Object> contentValues = new HashMap<>(); |
| 636 | + setFileContent(contentValues, properties, data, dataWriter); |
| 637 | + repo.getResourceResolver().create(mainResource, JcrConstants.JCR_CONTENT, contentValues); |
590 | 638 |
|
591 | | - repo.commit(String.format("updating file at path '%s'", path)); |
592 | | - repo.getLogger().info("Updated file at path '{}'", path); |
593 | | - } |
| 639 | + repo.commit(String.format("saving file at path '%s'", path)); |
| 640 | + repo.getLogger().info("Saved file at path '{}'", path); |
594 | 641 | } catch (PersistenceException e) { |
595 | 642 | throw new RepoException(String.format("Cannot save file at path '%s'!", path), e); |
596 | 643 | } |
597 | 644 | } |
598 | 645 |
|
599 | 646 | private void setFileContent( |
600 | | - Map<String, Object> contentValues, String mimeType, Object data, Consumer<OutputStream> dataWriter) { |
| 647 | + Map<String, Object> contentValues, |
| 648 | + Map<String, Object> props, |
| 649 | + InputStream data, |
| 650 | + Consumer<OutputStream> dataWriter) { |
| 651 | + contentValues.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE); |
| 652 | + contentValues.putAll(props); |
| 653 | + |
601 | 654 | if (dataWriter != null) { |
602 | | - setFileContent(contentValues, mimeType, dataWriter); |
| 655 | + final PipedInputStream pis = new PipedInputStream(); |
| 656 | + Executors.newSingleThreadExecutor().submit(() -> { |
| 657 | + try (PipedOutputStream pos = new PipedOutputStream(pis)) { |
| 658 | + dataWriter.accept(pos); |
| 659 | + } catch (Exception e) { |
| 660 | + throw new RepoException(String.format("Cannot write data to file at path '%s'!", path), e); |
| 661 | + } |
| 662 | + }); |
| 663 | + contentValues.put(JcrConstants.JCR_DATA, pis); |
603 | 664 | } else { |
604 | | - setFileContent(contentValues, mimeType, data); |
| 665 | + contentValues.put(JcrConstants.JCR_DATA, data); |
605 | 666 | } |
606 | 667 | } |
607 | 668 |
|
608 | | - private void setFileContent(Map<String, Object> contentValues, String mimeType, Object data) { |
609 | | - contentValues.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE); |
610 | | - contentValues.put(JcrConstants.JCR_ENCODING, "utf-8"); |
611 | | - contentValues.put(JcrConstants.JCR_MIMETYPE, mimeType); |
612 | | - contentValues.put(JcrConstants.JCR_DATA, data); |
613 | | - } |
614 | | - |
615 | | - // https://stackoverflow.com/a/27172165 |
616 | | - private void setFileContent(Map<String, Object> contentValues, String mimeType, Consumer<OutputStream> dataWriter) { |
617 | | - contentValues.put(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_RESOURCE); |
618 | | - contentValues.put(JcrConstants.JCR_ENCODING, "utf-8"); |
619 | | - contentValues.put(JcrConstants.JCR_MIMETYPE, mimeType); |
620 | | - final PipedInputStream pis = new PipedInputStream(); |
621 | | - Executors.newSingleThreadExecutor().submit(() -> { |
622 | | - try (PipedOutputStream pos = new PipedOutputStream(pis)) { |
623 | | - dataWriter.accept(pos); |
624 | | - } catch (Exception e) { |
625 | | - throw new RepoException(String.format("Cannot write data to file at path '%s'!", path), e); |
626 | | - } |
627 | | - }); |
628 | | - contentValues.put(JcrConstants.JCR_DATA, pis); |
629 | | - } |
630 | | - |
631 | 669 | public InputStream readFileAsStream() { |
632 | 670 | Resource resource = require(); |
633 | 671 | Resource contentResource = resource.getChild(JcrConstants.JCR_CONTENT); |
|
0 commit comments