How to Add and Remove MIME attachments correctly












0















I am adding MIME attachments to a document like this



try{
var d = database.getView("Main").getFirstDocument()
var it = d.getFirstItem("Body")
var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
var streamDOC:NotesStream = session.createStream()

streamDOC.setContents(att.getInputStream())


var newd;
newd = database.getView("NewD").getFirstDocument()
if(newd==null){
newd = database.createDocument()
newd.replaceItemValue("Form","Main")
var me = newd.createMIMEEntity("Body")
}else{
var me = newd.getMIMEEntity("Body")
}

var filename = "test.pdf"
var mc = me.createChildEntity();
var he = mc.createHeader("Content-Disposition")
he.setHeaderVal("attachment; filename="" + filename + """);
he = mc.createHeader("Content-ID");
he.setHeaderVal( "<" + filename + ">" );
mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
newd.save()
print("success")
}catch(e){
print("fail " + e)
}


and in a repeat I provide a delete button



var eo = nd.getDocument().getAttachment(att)
eo.remove()
nd.save()


the attachment are removed from the document, in Ytria I can see that the $FILE items are removed but not the BODY items. the problem with this is that if I add a new attachment to the same document all the attachments I removed previously come back



This is how the document looks before removing the attachments.



The file size here is unfortnuately 0Kb because I used the wrong screenshot. from the beginnin all $File items have correct size



enter image description here



This is how the document look after I removed the attachments (using the script above)



enter image description here



This is what the document look like after I add one attachment (using the script above) after I removed them



enter image description here




  • Could I be doing something wrong when adding or removing the attachments? (see
    script)

  • It does not seem to matter if the Body field has the "store
    content as MIME" option set or not

  • see also this question
    How to Add and Remove attachments using MIME










share|improve this question





























    0















    I am adding MIME attachments to a document like this



    try{
    var d = database.getView("Main").getFirstDocument()
    var it = d.getFirstItem("Body")
    var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
    var streamDOC:NotesStream = session.createStream()

    streamDOC.setContents(att.getInputStream())


    var newd;
    newd = database.getView("NewD").getFirstDocument()
    if(newd==null){
    newd = database.createDocument()
    newd.replaceItemValue("Form","Main")
    var me = newd.createMIMEEntity("Body")
    }else{
    var me = newd.getMIMEEntity("Body")
    }

    var filename = "test.pdf"
    var mc = me.createChildEntity();
    var he = mc.createHeader("Content-Disposition")
    he.setHeaderVal("attachment; filename="" + filename + """);
    he = mc.createHeader("Content-ID");
    he.setHeaderVal( "<" + filename + ">" );
    mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
    newd.save()
    print("success")
    }catch(e){
    print("fail " + e)
    }


    and in a repeat I provide a delete button



    var eo = nd.getDocument().getAttachment(att)
    eo.remove()
    nd.save()


    the attachment are removed from the document, in Ytria I can see that the $FILE items are removed but not the BODY items. the problem with this is that if I add a new attachment to the same document all the attachments I removed previously come back



    This is how the document looks before removing the attachments.



    The file size here is unfortnuately 0Kb because I used the wrong screenshot. from the beginnin all $File items have correct size



    enter image description here



    This is how the document look after I removed the attachments (using the script above)



    enter image description here



    This is what the document look like after I add one attachment (using the script above) after I removed them



    enter image description here




    • Could I be doing something wrong when adding or removing the attachments? (see
      script)

    • It does not seem to matter if the Body field has the "store
      content as MIME" option set or not

    • see also this question
      How to Add and Remove attachments using MIME










    share|improve this question



























      0












      0








      0








      I am adding MIME attachments to a document like this



      try{
      var d = database.getView("Main").getFirstDocument()
      var it = d.getFirstItem("Body")
      var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
      var streamDOC:NotesStream = session.createStream()

      streamDOC.setContents(att.getInputStream())


      var newd;
      newd = database.getView("NewD").getFirstDocument()
      if(newd==null){
      newd = database.createDocument()
      newd.replaceItemValue("Form","Main")
      var me = newd.createMIMEEntity("Body")
      }else{
      var me = newd.getMIMEEntity("Body")
      }

      var filename = "test.pdf"
      var mc = me.createChildEntity();
      var he = mc.createHeader("Content-Disposition")
      he.setHeaderVal("attachment; filename="" + filename + """);
      he = mc.createHeader("Content-ID");
      he.setHeaderVal( "<" + filename + ">" );
      mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
      newd.save()
      print("success")
      }catch(e){
      print("fail " + e)
      }


      and in a repeat I provide a delete button



      var eo = nd.getDocument().getAttachment(att)
      eo.remove()
      nd.save()


      the attachment are removed from the document, in Ytria I can see that the $FILE items are removed but not the BODY items. the problem with this is that if I add a new attachment to the same document all the attachments I removed previously come back



      This is how the document looks before removing the attachments.



      The file size here is unfortnuately 0Kb because I used the wrong screenshot. from the beginnin all $File items have correct size



      enter image description here



      This is how the document look after I removed the attachments (using the script above)



      enter image description here



      This is what the document look like after I add one attachment (using the script above) after I removed them



      enter image description here




      • Could I be doing something wrong when adding or removing the attachments? (see
        script)

      • It does not seem to matter if the Body field has the "store
        content as MIME" option set or not

      • see also this question
        How to Add and Remove attachments using MIME










      share|improve this question
















      I am adding MIME attachments to a document like this



      try{
      var d = database.getView("Main").getFirstDocument()
      var it = d.getFirstItem("Body")
      var att:NotesEmbeddedObject = it.getEmbeddedObject("mydoc.docx")
      var streamDOC:NotesStream = session.createStream()

      streamDOC.setContents(att.getInputStream())


      var newd;
      newd = database.getView("NewD").getFirstDocument()
      if(newd==null){
      newd = database.createDocument()
      newd.replaceItemValue("Form","Main")
      var me = newd.createMIMEEntity("Body")
      }else{
      var me = newd.getMIMEEntity("Body")
      }

      var filename = "test.pdf"
      var mc = me.createChildEntity();
      var he = mc.createHeader("Content-Disposition")
      he.setHeaderVal("attachment; filename="" + filename + """);
      he = mc.createHeader("Content-ID");
      he.setHeaderVal( "<" + filename + ">" );
      mc.setContentFromBytes(streamDOC, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", NotesMIMEEntity.ENC_IDENTITY_8BIT);
      newd.save()
      print("success")
      }catch(e){
      print("fail " + e)
      }


      and in a repeat I provide a delete button



      var eo = nd.getDocument().getAttachment(att)
      eo.remove()
      nd.save()


      the attachment are removed from the document, in Ytria I can see that the $FILE items are removed but not the BODY items. the problem with this is that if I add a new attachment to the same document all the attachments I removed previously come back



      This is how the document looks before removing the attachments.



      The file size here is unfortnuately 0Kb because I used the wrong screenshot. from the beginnin all $File items have correct size



      enter image description here



      This is how the document look after I removed the attachments (using the script above)



      enter image description here



      This is what the document look like after I add one attachment (using the script above) after I removed them



      enter image description here




      • Could I be doing something wrong when adding or removing the attachments? (see
        script)

      • It does not seem to matter if the Body field has the "store
        content as MIME" option set or not

      • see also this question
        How to Add and Remove attachments using MIME







      xpages attachment mime






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 22 '18 at 13:22







      Thomas Adrian

















      asked Nov 22 '18 at 12:51









      Thomas AdrianThomas Adrian

      2,49422448




      2,49422448
























          1 Answer
          1






          active

          oldest

          votes


















          1














          If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?



          I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:



          I have an enum that helps me navigate through the various MIME types. In this case you are dealing with ATTACHMENT:



          public enum MimeContentType {

          ATTACHMENT("attachment") {

          @Override
          public boolean matches(String headers) {
          int score = 0;

          for (String header : headers) {
          if (header.startsWith("Content-Disposition")) {
          score++;
          }

          if (header.contains("attachment")) {
          score++;
          }

          if (header.contains("filename")) {
          score++;
          }

          if (score == 3) {
          return true;
          }
          }

          return false;
          }

          },
          TEXT("text"),
          TEXT_HTML("text/html"),
          TEXT_PLAIN("text/plain");

          private final String type;

          private MimeContentType(String type) {
          this.type = type;
          }

          public boolean matches(String headers) {
          for (String header : headers) {
          if (header.startsWith("Content-Type") && header.contains(type)) {
          return true;
          }
          }

          return false;
          }

          }


          Then some helper classes:



          @FunctionalInterface
          public interface ThrowableConsumer<T> extends Consumer<T> {

          @Override
          default void accept(final T t) {
          try {
          acceptOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          void acceptOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableFunction<T, R> extends Function<T, R> {

          @Override
          default R apply(T t) {
          try {
          return applyOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          R applyOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowablePredicate<T> extends Predicate<T> {

          @Override
          default boolean test(T t) {
          try {
          return testOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          boolean testOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableSupplier<T> extends Supplier<T> {

          @Override
          default T get() {
          try {
          return getOrThrow();
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          T getOrThrow() throws Throwable;

          }

          public enum DominoUtil {
          ;

          private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();

          static {
          MIME_FILTERED_HEADERS.add("Content-Type");
          MIME_FILTERED_HEADERS.add("Content-Disposition");
          }

          public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
          MimeContentType contentType) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(contentType, "Content type cannot be null");

          List<MIMEEntity> subentities = new ArrayList<>();
          MIMEEntity nextEntity = null;

          try {
          nextEntity = entity.getNextEntity();

          while (nextEntity != null) {
          String entityFilteredHeaders = nextEntity
          .getSomeHeaders(MIME_FILTERED_HEADERS, true)
          .split("\n");

          if (contentType.matches(entityFilteredHeaders)) {
          subentities.add(nextEntity);
          }

          nextEntity = nextEntity.getNextEntity();
          }
          } finally {
          DominoUtil.recycle(nextEntity);
          }

          return subentities;
          }

          public final static MIMEEntity getMimeEntity(Document doc, String itemName,
          boolean createOnFail) throws NotesException {
          if (itemName == null) {
          throw new NullPointerException("Invalid MIME entity item name");
          }

          MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);

          if (mimeEntity == null) {
          if (doc.hasItem(itemName)) {
          doc.removeItem(itemName);
          }

          if (createOnFail) {
          mimeEntity = doc.createMIMEEntity(itemName);
          }
          }

          return mimeEntity;
          }

          public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");

          return getMimeEntityHeaderValAndParams(
          entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
          .map(s -> {
          Matcher m = Pattern.compile("filename=['"]?([^'"\s]+)").matcher(s);
          m.find();
          return m.group(1);
          });
          }

          public static Optional<String> getMimeEntityHeaderValAndParams(
          MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(matcher, "Matcher cannot be null");

          Vector<?> headers = entity.getHeaderObjects();

          try {
          return headers
          .stream()
          .map(MIMEHeader.class::cast)
          .filter(matcher)
          .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
          .findFirst();
          } finally {
          recycle(headers);
          }
          }

          public static void recycle(Base... bases) {
          for (Base base : bases) {
          if (base != null) {
          try {
          base.recycle();
          } catch (Exception e) {
          // Do nothing
          }
          }
          }
          }

          public static void recycle(Collection<? extends Object> objs) {
          objs.stream()
          .filter(o -> o instanceof Base)
          .map(o -> (Base) o)
          .forEach(DominoUtil::recycle);
          }

          }


          Finally the method that would do the job:



          public class Example {

          public static void yourEntryPoint() {
          try {
          // The last param is just a way to create an attachment from text
          // You have InputStream to pass along obviously
          addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
          addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
          addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
          removeAttachment(doc, "Body", "fake2.txt");
          removeAttachment(doc, "Body", "fake3.txt");

          } catch (NotesException e) {
          throw new RuntimeException(e);
          }
          }

          private static void addAttachment(Document doc, String itemName, String fileName, String data)
          throws NotesException {
          MIMEEntity mimeEntity = null;
          Stream stm = null;

          try {
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          MIMEEntity attachmentEntity = null;

          if (optAttEntity.isPresent()) {
          attachmentEntity = optAttEntity.get();
          } else {
          attachmentEntity = mimeEntity.createChildEntity();
          MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
          header.setHeaderValAndParams("attachment; filename="" + fileName + """);
          }

          stm = doc.getParentDatabase().getParent().createStream();
          stm.writeText(data);

          attachmentEntity.setContentFromBytes(stm,
          "application/octet-stream",
          MIMEEntity.ENC_IDENTITY_BINARY);

          stm.close();

          doc.closeMIMEEntities(true, itemName);
          } finally {
          DominoUtil.recycle(stm);
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static void removeAttachment(Document doc, String itemName, String fileName)
          throws NotesException {
          MIMEEntity mimeEntity = null;

          try {
          // Get MIME entity
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          if (!optAttEntity.isPresent()) {
          return;
          }

          optAttEntity.get().remove();

          // Header cleaning on empty entity
          if (mimeEntity.getFirstChildEntity() != null) {
          doc.closeMIMEEntities(true, itemName);
          } else {
          mimeEntity.remove();
          }
          } finally {
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
          throws NotesException {
          return DominoUtil
          .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
          .stream()
          .filter((ThrowablePredicate<MIMEEntity>) mime -> {
          Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);

          return opt.isPresent() && opt.get().equals(fileName);
          })
          .findFirst();
          }

          }





          share|improve this answer


























          • thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

            – Thomas Adrian
            Nov 22 '18 at 16:49











          • Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

            – shillem
            Nov 22 '18 at 17:07













          • I get compile errors.

            – Thomas Adrian
            Nov 22 '18 at 17:12











          • Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

            – shillem
            Nov 22 '18 at 17:14











          • No, look at the method signature i showed in the comment. I am using DDE10

            – Thomas Adrian
            Nov 22 '18 at 17:27











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53431447%2fhow-to-add-and-remove-mime-attachments-correctly%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?



          I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:



          I have an enum that helps me navigate through the various MIME types. In this case you are dealing with ATTACHMENT:



          public enum MimeContentType {

          ATTACHMENT("attachment") {

          @Override
          public boolean matches(String headers) {
          int score = 0;

          for (String header : headers) {
          if (header.startsWith("Content-Disposition")) {
          score++;
          }

          if (header.contains("attachment")) {
          score++;
          }

          if (header.contains("filename")) {
          score++;
          }

          if (score == 3) {
          return true;
          }
          }

          return false;
          }

          },
          TEXT("text"),
          TEXT_HTML("text/html"),
          TEXT_PLAIN("text/plain");

          private final String type;

          private MimeContentType(String type) {
          this.type = type;
          }

          public boolean matches(String headers) {
          for (String header : headers) {
          if (header.startsWith("Content-Type") && header.contains(type)) {
          return true;
          }
          }

          return false;
          }

          }


          Then some helper classes:



          @FunctionalInterface
          public interface ThrowableConsumer<T> extends Consumer<T> {

          @Override
          default void accept(final T t) {
          try {
          acceptOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          void acceptOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableFunction<T, R> extends Function<T, R> {

          @Override
          default R apply(T t) {
          try {
          return applyOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          R applyOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowablePredicate<T> extends Predicate<T> {

          @Override
          default boolean test(T t) {
          try {
          return testOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          boolean testOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableSupplier<T> extends Supplier<T> {

          @Override
          default T get() {
          try {
          return getOrThrow();
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          T getOrThrow() throws Throwable;

          }

          public enum DominoUtil {
          ;

          private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();

          static {
          MIME_FILTERED_HEADERS.add("Content-Type");
          MIME_FILTERED_HEADERS.add("Content-Disposition");
          }

          public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
          MimeContentType contentType) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(contentType, "Content type cannot be null");

          List<MIMEEntity> subentities = new ArrayList<>();
          MIMEEntity nextEntity = null;

          try {
          nextEntity = entity.getNextEntity();

          while (nextEntity != null) {
          String entityFilteredHeaders = nextEntity
          .getSomeHeaders(MIME_FILTERED_HEADERS, true)
          .split("\n");

          if (contentType.matches(entityFilteredHeaders)) {
          subentities.add(nextEntity);
          }

          nextEntity = nextEntity.getNextEntity();
          }
          } finally {
          DominoUtil.recycle(nextEntity);
          }

          return subentities;
          }

          public final static MIMEEntity getMimeEntity(Document doc, String itemName,
          boolean createOnFail) throws NotesException {
          if (itemName == null) {
          throw new NullPointerException("Invalid MIME entity item name");
          }

          MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);

          if (mimeEntity == null) {
          if (doc.hasItem(itemName)) {
          doc.removeItem(itemName);
          }

          if (createOnFail) {
          mimeEntity = doc.createMIMEEntity(itemName);
          }
          }

          return mimeEntity;
          }

          public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");

          return getMimeEntityHeaderValAndParams(
          entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
          .map(s -> {
          Matcher m = Pattern.compile("filename=['"]?([^'"\s]+)").matcher(s);
          m.find();
          return m.group(1);
          });
          }

          public static Optional<String> getMimeEntityHeaderValAndParams(
          MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(matcher, "Matcher cannot be null");

          Vector<?> headers = entity.getHeaderObjects();

          try {
          return headers
          .stream()
          .map(MIMEHeader.class::cast)
          .filter(matcher)
          .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
          .findFirst();
          } finally {
          recycle(headers);
          }
          }

          public static void recycle(Base... bases) {
          for (Base base : bases) {
          if (base != null) {
          try {
          base.recycle();
          } catch (Exception e) {
          // Do nothing
          }
          }
          }
          }

          public static void recycle(Collection<? extends Object> objs) {
          objs.stream()
          .filter(o -> o instanceof Base)
          .map(o -> (Base) o)
          .forEach(DominoUtil::recycle);
          }

          }


          Finally the method that would do the job:



          public class Example {

          public static void yourEntryPoint() {
          try {
          // The last param is just a way to create an attachment from text
          // You have InputStream to pass along obviously
          addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
          addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
          addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
          removeAttachment(doc, "Body", "fake2.txt");
          removeAttachment(doc, "Body", "fake3.txt");

          } catch (NotesException e) {
          throw new RuntimeException(e);
          }
          }

          private static void addAttachment(Document doc, String itemName, String fileName, String data)
          throws NotesException {
          MIMEEntity mimeEntity = null;
          Stream stm = null;

          try {
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          MIMEEntity attachmentEntity = null;

          if (optAttEntity.isPresent()) {
          attachmentEntity = optAttEntity.get();
          } else {
          attachmentEntity = mimeEntity.createChildEntity();
          MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
          header.setHeaderValAndParams("attachment; filename="" + fileName + """);
          }

          stm = doc.getParentDatabase().getParent().createStream();
          stm.writeText(data);

          attachmentEntity.setContentFromBytes(stm,
          "application/octet-stream",
          MIMEEntity.ENC_IDENTITY_BINARY);

          stm.close();

          doc.closeMIMEEntities(true, itemName);
          } finally {
          DominoUtil.recycle(stm);
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static void removeAttachment(Document doc, String itemName, String fileName)
          throws NotesException {
          MIMEEntity mimeEntity = null;

          try {
          // Get MIME entity
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          if (!optAttEntity.isPresent()) {
          return;
          }

          optAttEntity.get().remove();

          // Header cleaning on empty entity
          if (mimeEntity.getFirstChildEntity() != null) {
          doc.closeMIMEEntities(true, itemName);
          } else {
          mimeEntity.remove();
          }
          } finally {
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
          throws NotesException {
          return DominoUtil
          .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
          .stream()
          .filter((ThrowablePredicate<MIMEEntity>) mime -> {
          Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);

          return opt.isPresent() && opt.get().equals(fileName);
          })
          .findFirst();
          }

          }





          share|improve this answer


























          • thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

            – Thomas Adrian
            Nov 22 '18 at 16:49











          • Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

            – shillem
            Nov 22 '18 at 17:07













          • I get compile errors.

            – Thomas Adrian
            Nov 22 '18 at 17:12











          • Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

            – shillem
            Nov 22 '18 at 17:14











          • No, look at the method signature i showed in the comment. I am using DDE10

            – Thomas Adrian
            Nov 22 '18 at 17:27
















          1














          If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?



          I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:



          I have an enum that helps me navigate through the various MIME types. In this case you are dealing with ATTACHMENT:



          public enum MimeContentType {

          ATTACHMENT("attachment") {

          @Override
          public boolean matches(String headers) {
          int score = 0;

          for (String header : headers) {
          if (header.startsWith("Content-Disposition")) {
          score++;
          }

          if (header.contains("attachment")) {
          score++;
          }

          if (header.contains("filename")) {
          score++;
          }

          if (score == 3) {
          return true;
          }
          }

          return false;
          }

          },
          TEXT("text"),
          TEXT_HTML("text/html"),
          TEXT_PLAIN("text/plain");

          private final String type;

          private MimeContentType(String type) {
          this.type = type;
          }

          public boolean matches(String headers) {
          for (String header : headers) {
          if (header.startsWith("Content-Type") && header.contains(type)) {
          return true;
          }
          }

          return false;
          }

          }


          Then some helper classes:



          @FunctionalInterface
          public interface ThrowableConsumer<T> extends Consumer<T> {

          @Override
          default void accept(final T t) {
          try {
          acceptOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          void acceptOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableFunction<T, R> extends Function<T, R> {

          @Override
          default R apply(T t) {
          try {
          return applyOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          R applyOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowablePredicate<T> extends Predicate<T> {

          @Override
          default boolean test(T t) {
          try {
          return testOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          boolean testOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableSupplier<T> extends Supplier<T> {

          @Override
          default T get() {
          try {
          return getOrThrow();
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          T getOrThrow() throws Throwable;

          }

          public enum DominoUtil {
          ;

          private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();

          static {
          MIME_FILTERED_HEADERS.add("Content-Type");
          MIME_FILTERED_HEADERS.add("Content-Disposition");
          }

          public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
          MimeContentType contentType) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(contentType, "Content type cannot be null");

          List<MIMEEntity> subentities = new ArrayList<>();
          MIMEEntity nextEntity = null;

          try {
          nextEntity = entity.getNextEntity();

          while (nextEntity != null) {
          String entityFilteredHeaders = nextEntity
          .getSomeHeaders(MIME_FILTERED_HEADERS, true)
          .split("\n");

          if (contentType.matches(entityFilteredHeaders)) {
          subentities.add(nextEntity);
          }

          nextEntity = nextEntity.getNextEntity();
          }
          } finally {
          DominoUtil.recycle(nextEntity);
          }

          return subentities;
          }

          public final static MIMEEntity getMimeEntity(Document doc, String itemName,
          boolean createOnFail) throws NotesException {
          if (itemName == null) {
          throw new NullPointerException("Invalid MIME entity item name");
          }

          MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);

          if (mimeEntity == null) {
          if (doc.hasItem(itemName)) {
          doc.removeItem(itemName);
          }

          if (createOnFail) {
          mimeEntity = doc.createMIMEEntity(itemName);
          }
          }

          return mimeEntity;
          }

          public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");

          return getMimeEntityHeaderValAndParams(
          entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
          .map(s -> {
          Matcher m = Pattern.compile("filename=['"]?([^'"\s]+)").matcher(s);
          m.find();
          return m.group(1);
          });
          }

          public static Optional<String> getMimeEntityHeaderValAndParams(
          MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(matcher, "Matcher cannot be null");

          Vector<?> headers = entity.getHeaderObjects();

          try {
          return headers
          .stream()
          .map(MIMEHeader.class::cast)
          .filter(matcher)
          .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
          .findFirst();
          } finally {
          recycle(headers);
          }
          }

          public static void recycle(Base... bases) {
          for (Base base : bases) {
          if (base != null) {
          try {
          base.recycle();
          } catch (Exception e) {
          // Do nothing
          }
          }
          }
          }

          public static void recycle(Collection<? extends Object> objs) {
          objs.stream()
          .filter(o -> o instanceof Base)
          .map(o -> (Base) o)
          .forEach(DominoUtil::recycle);
          }

          }


          Finally the method that would do the job:



          public class Example {

          public static void yourEntryPoint() {
          try {
          // The last param is just a way to create an attachment from text
          // You have InputStream to pass along obviously
          addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
          addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
          addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
          removeAttachment(doc, "Body", "fake2.txt");
          removeAttachment(doc, "Body", "fake3.txt");

          } catch (NotesException e) {
          throw new RuntimeException(e);
          }
          }

          private static void addAttachment(Document doc, String itemName, String fileName, String data)
          throws NotesException {
          MIMEEntity mimeEntity = null;
          Stream stm = null;

          try {
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          MIMEEntity attachmentEntity = null;

          if (optAttEntity.isPresent()) {
          attachmentEntity = optAttEntity.get();
          } else {
          attachmentEntity = mimeEntity.createChildEntity();
          MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
          header.setHeaderValAndParams("attachment; filename="" + fileName + """);
          }

          stm = doc.getParentDatabase().getParent().createStream();
          stm.writeText(data);

          attachmentEntity.setContentFromBytes(stm,
          "application/octet-stream",
          MIMEEntity.ENC_IDENTITY_BINARY);

          stm.close();

          doc.closeMIMEEntities(true, itemName);
          } finally {
          DominoUtil.recycle(stm);
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static void removeAttachment(Document doc, String itemName, String fileName)
          throws NotesException {
          MIMEEntity mimeEntity = null;

          try {
          // Get MIME entity
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          if (!optAttEntity.isPresent()) {
          return;
          }

          optAttEntity.get().remove();

          // Header cleaning on empty entity
          if (mimeEntity.getFirstChildEntity() != null) {
          doc.closeMIMEEntities(true, itemName);
          } else {
          mimeEntity.remove();
          }
          } finally {
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
          throws NotesException {
          return DominoUtil
          .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
          .stream()
          .filter((ThrowablePredicate<MIMEEntity>) mime -> {
          Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);

          return opt.isPresent() && opt.get().equals(fileName);
          })
          .findFirst();
          }

          }





          share|improve this answer


























          • thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

            – Thomas Adrian
            Nov 22 '18 at 16:49











          • Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

            – shillem
            Nov 22 '18 at 17:07













          • I get compile errors.

            – Thomas Adrian
            Nov 22 '18 at 17:12











          • Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

            – shillem
            Nov 22 '18 at 17:14











          • No, look at the method signature i showed in the comment. I am using DDE10

            – Thomas Adrian
            Nov 22 '18 at 17:27














          1












          1








          1







          If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?



          I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:



          I have an enum that helps me navigate through the various MIME types. In this case you are dealing with ATTACHMENT:



          public enum MimeContentType {

          ATTACHMENT("attachment") {

          @Override
          public boolean matches(String headers) {
          int score = 0;

          for (String header : headers) {
          if (header.startsWith("Content-Disposition")) {
          score++;
          }

          if (header.contains("attachment")) {
          score++;
          }

          if (header.contains("filename")) {
          score++;
          }

          if (score == 3) {
          return true;
          }
          }

          return false;
          }

          },
          TEXT("text"),
          TEXT_HTML("text/html"),
          TEXT_PLAIN("text/plain");

          private final String type;

          private MimeContentType(String type) {
          this.type = type;
          }

          public boolean matches(String headers) {
          for (String header : headers) {
          if (header.startsWith("Content-Type") && header.contains(type)) {
          return true;
          }
          }

          return false;
          }

          }


          Then some helper classes:



          @FunctionalInterface
          public interface ThrowableConsumer<T> extends Consumer<T> {

          @Override
          default void accept(final T t) {
          try {
          acceptOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          void acceptOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableFunction<T, R> extends Function<T, R> {

          @Override
          default R apply(T t) {
          try {
          return applyOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          R applyOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowablePredicate<T> extends Predicate<T> {

          @Override
          default boolean test(T t) {
          try {
          return testOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          boolean testOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableSupplier<T> extends Supplier<T> {

          @Override
          default T get() {
          try {
          return getOrThrow();
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          T getOrThrow() throws Throwable;

          }

          public enum DominoUtil {
          ;

          private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();

          static {
          MIME_FILTERED_HEADERS.add("Content-Type");
          MIME_FILTERED_HEADERS.add("Content-Disposition");
          }

          public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
          MimeContentType contentType) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(contentType, "Content type cannot be null");

          List<MIMEEntity> subentities = new ArrayList<>();
          MIMEEntity nextEntity = null;

          try {
          nextEntity = entity.getNextEntity();

          while (nextEntity != null) {
          String entityFilteredHeaders = nextEntity
          .getSomeHeaders(MIME_FILTERED_HEADERS, true)
          .split("\n");

          if (contentType.matches(entityFilteredHeaders)) {
          subentities.add(nextEntity);
          }

          nextEntity = nextEntity.getNextEntity();
          }
          } finally {
          DominoUtil.recycle(nextEntity);
          }

          return subentities;
          }

          public final static MIMEEntity getMimeEntity(Document doc, String itemName,
          boolean createOnFail) throws NotesException {
          if (itemName == null) {
          throw new NullPointerException("Invalid MIME entity item name");
          }

          MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);

          if (mimeEntity == null) {
          if (doc.hasItem(itemName)) {
          doc.removeItem(itemName);
          }

          if (createOnFail) {
          mimeEntity = doc.createMIMEEntity(itemName);
          }
          }

          return mimeEntity;
          }

          public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");

          return getMimeEntityHeaderValAndParams(
          entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
          .map(s -> {
          Matcher m = Pattern.compile("filename=['"]?([^'"\s]+)").matcher(s);
          m.find();
          return m.group(1);
          });
          }

          public static Optional<String> getMimeEntityHeaderValAndParams(
          MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(matcher, "Matcher cannot be null");

          Vector<?> headers = entity.getHeaderObjects();

          try {
          return headers
          .stream()
          .map(MIMEHeader.class::cast)
          .filter(matcher)
          .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
          .findFirst();
          } finally {
          recycle(headers);
          }
          }

          public static void recycle(Base... bases) {
          for (Base base : bases) {
          if (base != null) {
          try {
          base.recycle();
          } catch (Exception e) {
          // Do nothing
          }
          }
          }
          }

          public static void recycle(Collection<? extends Object> objs) {
          objs.stream()
          .filter(o -> o instanceof Base)
          .map(o -> (Base) o)
          .forEach(DominoUtil::recycle);
          }

          }


          Finally the method that would do the job:



          public class Example {

          public static void yourEntryPoint() {
          try {
          // The last param is just a way to create an attachment from text
          // You have InputStream to pass along obviously
          addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
          addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
          addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
          removeAttachment(doc, "Body", "fake2.txt");
          removeAttachment(doc, "Body", "fake3.txt");

          } catch (NotesException e) {
          throw new RuntimeException(e);
          }
          }

          private static void addAttachment(Document doc, String itemName, String fileName, String data)
          throws NotesException {
          MIMEEntity mimeEntity = null;
          Stream stm = null;

          try {
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          MIMEEntity attachmentEntity = null;

          if (optAttEntity.isPresent()) {
          attachmentEntity = optAttEntity.get();
          } else {
          attachmentEntity = mimeEntity.createChildEntity();
          MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
          header.setHeaderValAndParams("attachment; filename="" + fileName + """);
          }

          stm = doc.getParentDatabase().getParent().createStream();
          stm.writeText(data);

          attachmentEntity.setContentFromBytes(stm,
          "application/octet-stream",
          MIMEEntity.ENC_IDENTITY_BINARY);

          stm.close();

          doc.closeMIMEEntities(true, itemName);
          } finally {
          DominoUtil.recycle(stm);
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static void removeAttachment(Document doc, String itemName, String fileName)
          throws NotesException {
          MIMEEntity mimeEntity = null;

          try {
          // Get MIME entity
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          if (!optAttEntity.isPresent()) {
          return;
          }

          optAttEntity.get().remove();

          // Header cleaning on empty entity
          if (mimeEntity.getFirstChildEntity() != null) {
          doc.closeMIMEEntities(true, itemName);
          } else {
          mimeEntity.remove();
          }
          } finally {
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
          throws NotesException {
          return DominoUtil
          .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
          .stream()
          .filter((ThrowablePredicate<MIMEEntity>) mime -> {
          Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);

          return opt.isPresent() && opt.get().equals(fileName);
          })
          .findFirst();
          }

          }





          share|improve this answer















          If you work with MIME methods to attach the file why not work with MIME methods to remove it as well?



          I use my own framework so the following code might give you the impression to overcomplicate things but hopefully you should get the gist of it:



          I have an enum that helps me navigate through the various MIME types. In this case you are dealing with ATTACHMENT:



          public enum MimeContentType {

          ATTACHMENT("attachment") {

          @Override
          public boolean matches(String headers) {
          int score = 0;

          for (String header : headers) {
          if (header.startsWith("Content-Disposition")) {
          score++;
          }

          if (header.contains("attachment")) {
          score++;
          }

          if (header.contains("filename")) {
          score++;
          }

          if (score == 3) {
          return true;
          }
          }

          return false;
          }

          },
          TEXT("text"),
          TEXT_HTML("text/html"),
          TEXT_PLAIN("text/plain");

          private final String type;

          private MimeContentType(String type) {
          this.type = type;
          }

          public boolean matches(String headers) {
          for (String header : headers) {
          if (header.startsWith("Content-Type") && header.contains(type)) {
          return true;
          }
          }

          return false;
          }

          }


          Then some helper classes:



          @FunctionalInterface
          public interface ThrowableConsumer<T> extends Consumer<T> {

          @Override
          default void accept(final T t) {
          try {
          acceptOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          void acceptOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableFunction<T, R> extends Function<T, R> {

          @Override
          default R apply(T t) {
          try {
          return applyOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          R applyOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowablePredicate<T> extends Predicate<T> {

          @Override
          default boolean test(T t) {
          try {
          return testOrThrow(t);
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          boolean testOrThrow(T t) throws Throwable;

          }

          @FunctionalInterface
          public interface ThrowableSupplier<T> extends Supplier<T> {

          @Override
          default T get() {
          try {
          return getOrThrow();
          } catch (final Throwable e) {
          throw new RuntimeException(e);
          }
          }

          T getOrThrow() throws Throwable;

          }

          public enum DominoUtil {
          ;

          private static final Vector<String> MIME_FILTERED_HEADERS = new Vector<>();

          static {
          MIME_FILTERED_HEADERS.add("Content-Type");
          MIME_FILTERED_HEADERS.add("Content-Disposition");
          }

          public static List<MIMEEntity> getMimeEntitiesByContentType(MIMEEntity entity,
          MimeContentType contentType) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(contentType, "Content type cannot be null");

          List<MIMEEntity> subentities = new ArrayList<>();
          MIMEEntity nextEntity = null;

          try {
          nextEntity = entity.getNextEntity();

          while (nextEntity != null) {
          String entityFilteredHeaders = nextEntity
          .getSomeHeaders(MIME_FILTERED_HEADERS, true)
          .split("\n");

          if (contentType.matches(entityFilteredHeaders)) {
          subentities.add(nextEntity);
          }

          nextEntity = nextEntity.getNextEntity();
          }
          } finally {
          DominoUtil.recycle(nextEntity);
          }

          return subentities;
          }

          public final static MIMEEntity getMimeEntity(Document doc, String itemName,
          boolean createOnFail) throws NotesException {
          if (itemName == null) {
          throw new NullPointerException("Invalid MIME entity item name");
          }

          MIMEEntity mimeEntity = doc.getMIMEEntity(itemName);

          if (mimeEntity == null) {
          if (doc.hasItem(itemName)) {
          doc.removeItem(itemName);
          }

          if (createOnFail) {
          mimeEntity = doc.createMIMEEntity(itemName);
          }
          }

          return mimeEntity;
          }

          public static Optional<String> getMimeEntityAttachmentFilename(MIMEEntity entity) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");

          return getMimeEntityHeaderValAndParams(
          entity, (ThrowablePredicate<MIMEHeader>) h -> h.getHeaderVal().equals("attachment"))
          .map(s -> {
          Matcher m = Pattern.compile("filename=['"]?([^'"\s]+)").matcher(s);
          m.find();
          return m.group(1);
          });
          }

          public static Optional<String> getMimeEntityHeaderValAndParams(
          MIMEEntity entity, Predicate<MIMEHeader> matcher) throws NotesException {
          Objects.requireNonNull(entity, "Entity cannot be null");
          Objects.requireNonNull(matcher, "Matcher cannot be null");

          Vector<?> headers = entity.getHeaderObjects();

          try {
          return headers
          .stream()
          .map(MIMEHeader.class::cast)
          .filter(matcher)
          .map((ThrowableFunction<MIMEHeader, String>) MIMEHeader::getHeaderValAndParams)
          .findFirst();
          } finally {
          recycle(headers);
          }
          }

          public static void recycle(Base... bases) {
          for (Base base : bases) {
          if (base != null) {
          try {
          base.recycle();
          } catch (Exception e) {
          // Do nothing
          }
          }
          }
          }

          public static void recycle(Collection<? extends Object> objs) {
          objs.stream()
          .filter(o -> o instanceof Base)
          .map(o -> (Base) o)
          .forEach(DominoUtil::recycle);
          }

          }


          Finally the method that would do the job:



          public class Example {

          public static void yourEntryPoint() {
          try {
          // The last param is just a way to create an attachment from text
          // You have InputStream to pass along obviously
          addAttachment(doc, "Body", "fake1.txt", "this is fake text1");
          addAttachment(doc, "Body", "fake2.txt", "this is fake text2");
          addAttachment(doc, "Body", "fake3.txt", "this is fake text3");
          removeAttachment(doc, "Body", "fake2.txt");
          removeAttachment(doc, "Body", "fake3.txt");

          } catch (NotesException e) {
          throw new RuntimeException(e);
          }
          }

          private static void addAttachment(Document doc, String itemName, String fileName, String data)
          throws NotesException {
          MIMEEntity mimeEntity = null;
          Stream stm = null;

          try {
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          MIMEEntity attachmentEntity = null;

          if (optAttEntity.isPresent()) {
          attachmentEntity = optAttEntity.get();
          } else {
          attachmentEntity = mimeEntity.createChildEntity();
          MIMEHeader header = attachmentEntity.createHeader("Content-Disposition");
          header.setHeaderValAndParams("attachment; filename="" + fileName + """);
          }

          stm = doc.getParentDatabase().getParent().createStream();
          stm.writeText(data);

          attachmentEntity.setContentFromBytes(stm,
          "application/octet-stream",
          MIMEEntity.ENC_IDENTITY_BINARY);

          stm.close();

          doc.closeMIMEEntities(true, itemName);
          } finally {
          DominoUtil.recycle(stm);
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static void removeAttachment(Document doc, String itemName, String fileName)
          throws NotesException {
          MIMEEntity mimeEntity = null;

          try {
          // Get MIME entity
          mimeEntity = DominoUtil.getMimeEntity(doc, itemName, true);

          Optional<MIMEEntity> optAttEntity = getAttachmentMimeEntity(mimeEntity, fileName);

          if (!optAttEntity.isPresent()) {
          return;
          }

          optAttEntity.get().remove();

          // Header cleaning on empty entity
          if (mimeEntity.getFirstChildEntity() != null) {
          doc.closeMIMEEntities(true, itemName);
          } else {
          mimeEntity.remove();
          }
          } finally {
          DominoUtil.recycle(mimeEntity);
          }
          }

          private static Optional<MIMEEntity> getAttachmentMimeEntity(MIMEEntity root, String fileName)
          throws NotesException {
          return DominoUtil
          .getMimeEntitiesByContentType(root, MimeContentType.ATTACHMENT)
          .stream()
          .filter((ThrowablePredicate<MIMEEntity>) mime -> {
          Optional<String> opt = DominoUtil.getMimeEntityAttachmentFilename(mime);

          return opt.isPresent() && opt.get().equals(fileName);
          })
          .findFirst();
          }

          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 23 '18 at 15:43

























          answered Nov 22 '18 at 13:48









          shillemshillem

          1,195611




          1,195611













          • thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

            – Thomas Adrian
            Nov 22 '18 at 16:49











          • Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

            – shillem
            Nov 22 '18 at 17:07













          • I get compile errors.

            – Thomas Adrian
            Nov 22 '18 at 17:12











          • Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

            – shillem
            Nov 22 '18 at 17:14











          • No, look at the method signature i showed in the comment. I am using DDE10

            – Thomas Adrian
            Nov 22 '18 at 17:27



















          • thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

            – Thomas Adrian
            Nov 22 '18 at 16:49











          • Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

            – shillem
            Nov 22 '18 at 17:07













          • I get compile errors.

            – Thomas Adrian
            Nov 22 '18 at 17:12











          • Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

            – shillem
            Nov 22 '18 at 17:14











          • No, look at the method signature i showed in the comment. I am using DDE10

            – Thomas Adrian
            Nov 22 '18 at 17:27

















          thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

          – Thomas Adrian
          Nov 22 '18 at 16:49





          thanks, that could be helpful but your code is not complete public static Map<MimeContentType, List<MIMEEntity>> getMimeEntities(MIMEEntity entity, MimeContentType... contentTypes)

          – Thomas Adrian
          Nov 22 '18 at 16:49













          Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

          – shillem
          Nov 22 '18 at 17:07







          Sorry, I don’t understand what you mean by that. I put the code together by stripping all the rest of the code out but what remained seems complete to me. Am I blind?

          – shillem
          Nov 22 '18 at 17:07















          I get compile errors.

          – Thomas Adrian
          Nov 22 '18 at 17:12





          I get compile errors.

          – Thomas Adrian
          Nov 22 '18 at 17:12













          Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

          – shillem
          Nov 22 '18 at 17:14





          Ok, for sure I left out the import statements. What are the errors? Do you use iava8 or 6?

          – shillem
          Nov 22 '18 at 17:14













          No, look at the method signature i showed in the comment. I am using DDE10

          – Thomas Adrian
          Nov 22 '18 at 17:27





          No, look at the method signature i showed in the comment. I am using DDE10

          – Thomas Adrian
          Nov 22 '18 at 17:27




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53431447%2fhow-to-add-and-remove-mime-attachments-correctly%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Xamarin.form Move up view when keyboard appear

          Post-Redirect-Get with Spring WebFlux and Thymeleaf

          Anylogic : not able to use stopDelay()