Hankos.Net

an Hankos Ltd. subsidiary

Ulica 111 Nova, 31
11060 Belgrade
Serbia
Phone in Serbia+381-11-2790136
Phone in Germany+49-89-61079488
Contact us

How to read a text file attached to a Lotus Notes Document WITHOUT detaching it?

One of the biggest problems when dealing with file attachments in Lotus Notes documents is that you can't detach the files on the server. This is due to a setting on the Public Names & Address Book on the server. Usually the server's administrator will not allow the use of unrestricted agents so the agent's will not touch any file on the server (which is a good idea).

But in some cases you will need to detach a file on the server to work with. If the administrator won't put you in the group who are authorized to use unrestricted agents, or not willing to sign the agent then you will need to find a workaround. In some cases if you are using a server which is hosted by a 3rd party you will not always have the rights to use unrestricted Lotus Script or Java agents.

While looking for a solution on the web, I have tumbled over several articles where people are trying to do the same thing, for example this article on Techtarget.com: Can you use LotusScript to read a text file attached to a Notes doc?. One idea to get started is to check this excellent article from Jake Howlett on Codestore.net: Generating File Attachments in Agents Without Unrestricted Rights.  

I wanted to have a simpler solution and also have a better understanding of what has to be done, so I'm sharing this easy to understand workaround, it is simply for the Lotus Notes developers out there to get an idea on how to do it.

First, there is no way to read a file attached to a Lotus Notes Document using only LotusScript, you can get the attachments filename, delete or add attachment but not actually work with the attached file without detaching it. The solution is to get some help with a Java agent that allows us to do a lot more stuff on Lotus Notes & Domino.

We are going to use two Lotus agents to do that, the first one will be a LotusScript agent to get the data from the Notes Document and pass it to the Java agent which will read the file attached and return a string back to the LotusScript agent.

The first problem you will face by using two different agent's is to find a way to pass some data from one agent to the other, you could write the parameters you need in the Lotus Notes document but then you will face some other problems, for example the document date will be modified and the document will have to be replicated over all the replica's. So when running the LotusScript agent, we will create a temporary Parameter document and write all the parameter needed in some fields.

You will find below the LotusScript agent listing, in this example we want to get the data of the attached file name "test0.txt". This agent will create a parameter document and put the Document ID in a field, as well as the name of the file attachment to read.

Then we will pass this document to the Java agent and it will write the

Listing 1: LotusScript Agent: "ReadAttachmentLS"

Sub Initialize
   Dim s As New NotesSession
   Dim db As NotesDatabase
   Dim workspace As New NotesUIWorkspace
   Dim uidoc As NotesUIDocument
   Set uidoc = workspace.CurrentDocument
   Dim doc As NotesDocument
   Set doc = uidoc.Document
   Dim agent As NotesAgent
   Set db = s.CurrentDatabase

   'In this example we will read the data of a file attachment named 
   '"test0.txt"
   'This is done by calling a Java agent, which will read the attachment 
   'WITHOUT detaching
   'the file to the hard disk
   Dim theFileAttachmentToRead As String
   theFileAttachmentToRead = "test0.txt"
   
   'Populate the parameters to be used by the Java agent
   'As described here:
   'http://www.ibm.com/developerworks/lotus/library/ls-Run_and_RunOnServer/
   'index.html
   'It is off course better to create a parameter document as described in the
   'above URL, like this, for example,
   'the modification date won't be modified
   
   'Create document that will be used for parameter passing 
   Dim parameterDoc As NotesDocument
   Set parameterDoc = db.CreateDocument 
   
   'Add the field that will contain the value filename & Universal ID
   Dim item As NotesItem 
   Set item = parameterDoc.AppendItemValue("Filename", theFileAttachmentToRead)
   Set item = parameterDoc.AppendItemValue("UniversalID", doc.UniversalID)
   
   'Save the document 
   Call parameterDoc.save(True, False)
   
   'Set the parameter value of the parameter document
   Dim paramid As String
   paramid = parameterDoc.Noteid
   
   Set agent = db.GetAgent("ReadAttachmentJava")
   'Start agent and pass note ID of document
   'Use agent.RunOnServer(paramid) to run the agent on the server
   If agent.Run(paramid) = 0 Then
      Print "Agent ran - Success"
   Else
      Print "Agent did not run - Failure"
   End If
   
   'Delete in-memory document. This is necessary because we need to reload 
   'the document in order to get the latest data which the Java Agent has 
   'written into the parameter document
   Delete parameterDoc 
   
   'Get the result from the parameter document (the data from the file 
   'attachment)
   Dim theResult As String
   Set parameterDoc = db.GetDocumentByID(paramid)
   theResult = parameterDoc.Result(0)
   
   'Do whatever you need with the data
   'Your code goes here
   Print "parameterDoc: Result=" + theResult
   
   'When finished delete the temporary parameter document
   Call parameterDoc.RemovePermanently(True)
End Sub


Now we need to create a Java agent, which will read the parameter document to get the document ID and the name of the attachment to read from, we will use standard Java IO stream function to read the file, once it is read, we write the content in a result field in the previously passed parameter document.

Listing 2: Java Agent: "ReadAttachmentJava"

import lotus.domino.*;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class JavaAgent extends AgentBase {
   public void NotesMain() {
      try{
         Session session = getSession();
         AgentContext agentContext = session.getAgentContext();
         Database db = agentContext.getCurrentDatabase();
         Agent agent = agentContext.getCurrentAgent();

         //Get document used for passing data
         Document paramDoc = db.getDocumentByID(agent.getParameterDocID());

         //Get the Universal ID and the Document where the attachment
         //is located
         String UniversalID = paramDoc.getItemValueString("UniversalID");
         Document doc = db.getDocumentByUNID(UniversalID);

         //Get the attachment filename from the parameter document
         String filename = paramDoc.getItemValueString("Filename");
         EmbeddedObject obj = doc.getAttachment(filename);
 
         String theJavaResult = "";         
           if (obj != null) {
            paramDoc.replaceItemValue("theJavaResult", "Found " + 
            obj.getName());      
         }
 
         java.io.InputStream is = obj.getInputStream();
         String theResult = "";
         if (is != null) {
            //read the stream of the file
            theResult = convertStreamToString(is);
         } else 
            paramDoc.replaceItemValue("theJavaResult", "No 
            Attachment InputSource!");      
         //Destroy object
         obj.recycle();

         //Save the parameter Doc with the result
         //put the result into a temporary field
         paramDoc.replaceItemValue("Result", theResult);
         paramDoc.save();
      }
      //Catch if something wrong happens from Notes side like,
      //Database/view failed to open or invalid formula etc
      catch(NotesException e) {System.out.println(e.id + " " + e.text);}
      //Usual Java Exception class
      catch(Exception e) { e.printStackTrace(); }
   }

   public static String convertStreamToString(InputStream is) throws 
   Exception {
      BufferedReader reader = new BufferedReader(new InputStreamReader(is));
      StringBuilder sb = new StringBuilder();
      String line = null;
      while ((line = reader.readLine()) != null) {
         sb.append(line + "\n");
      }
      is.close();
      return sb.toString();
   }
}


Once the Java agent has finished, we return to the LotusScript agent and read the result field from the parameter document. There is the place where you write the code you want your agent to do with the data. Don't forget to delete the parameter document if you don't need it anymore.

So, I hope this will give you a simple idea on how you can read file attachments without detaching them and how to pass parameters from one agent to another.

Some of you will ask, why not use a Java Library instead of a Java agent? Well because at this time, LS2J (IBM's LotusScript To Java), won't allow you to have access to the documents or uidocuments directly, you will need to use a Java agent in order to get the NoteID from LotusScript.

This code has been tested on Lotus Domino & Notes version > 8.x.

Best regards,
Adel Habib

Reference:


a. TechTarget.com: Can you use LotusScript to read a text file attached to a Notes doc?
b. IBM.com: Run and RunOnServer: Adding Parameters
c. Codestore.net: Generating File Attachments in Agents Without Unrestricted Rights

Bookmark and Share