Zip Up and Save Space

Erwin van Hunen, 14 November 2001

Category: Java; Keywords: Zip attachments file body

When you have a database which stores a lot of unzipped attachments, wouldn't it be nice if you could have an agent which periodically runs over them and zips them all? Sure could save a lot of space.

Well, you can and it's not even that difficult. The nice thing is you don't even need Winzip or any other tools to do it, it's already built into the Domino server and client! The magic word is "Java". Java has built in classes for zipping and unzipping files, which we are going to use for this small agent. There is just one small caveat: it only runs on R5.03 servers and above.

First, some things you need to make sure you have so as to get this example up and running:

Create a database, and in that database create a form. Call it whatever you want. On the form, create a rich text field called "Body" (you can call it something else, but then you'll have to modify the agent code below). Also create a view that shows these documents. Now create an agent which should run manually from the actions menu on selected documents.

Copy and paste the code below in to the agent. Don't get scared if it doesn't make a whole lot of sense. There are plenty of comments in the .Java file you can download here - ZipUp.java


// Written by Erwin van Hunen
//
// In this example the agent is run manually from the actions menu on selected documents,
// but of course it would make much more sense to run it as a scheduled or triggered agent
// in the background

import lotus.domino.*;
import java.io.*;
import java.util.*;
import java.util.zip.*;

public class JavaAgent extends AgentBase {

public void NotesMain() {

try {
FileOutputStream fos;
Item item;
RichTextItem rtitem;
String attachmentname;
Vector items;
String archivename;
byte b[] = new byte[512];

Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Database db = agentContext.getCurrentDatabase();

DocumentCollection col = agentContext.getUnprocessedDocuments();

Document doc = col.getFirstDocument();
while (doc != null)
{
archivename = session.getEnvironmentString("Directory",true) + "\\" + doc.getNoteID() + ".zip";

fos = new FileOutputStream(archivename);

ZipOutputStream zout = new ZipOutputStream(fos);

rtitem = (RichTextItem) doc.getFirstItem("Body");

items = doc.getItems();
for (int i=0; i<items.size(); i++) {
item = (Item) items.elementAt(i);
if(item.getType() == Item.ATTACHMENT)
{
if (item.getValueString().length() != 0)
{
attachmentname = item.getValueString();

EmbeddedObject attachment = (EmbeddedObject) doc.getAttachment(attachmentname);

InputStream in = attachment.getInputStream();

ZipEntry e = new ZipEntry(attachment.getName().replace(File.separatorChar,'/'));

zout.putNextEntry(e);
int len=0;

while((len=in.read(b)) != -1)
{
zout.write(b,0,len);
}
zout.closeEntry();
attachment.remove();
}
}
}
zout.close();
fos.close();
doc.replaceItemValue("Body","");
rtitem.embedObject(EmbeddedObject.EMBED_ATTACHMENT, null, archivename, archivename);

doc.save(true);

File zipfile = new File(archivename);
zipfile.delete();

doc = col.getNextDocument(doc);
}

} catch (Exception e) {
e.printStackTrace();
}

}
}

Trying the agent:

Create a document in the database and attach some files in the body field. Save the document, close it, select it in the view and run the agent from the actions menu. When the agent finishes, open the document and you should see a zip file instead of your attachments.

Basically this is what happens when you run the agent:

Domino creates an empty zipfile in the Notes\Data directory which is named after the NoteID of the document. Then it loops through all the attachments on the document and add them to the zipfile. Finally, it deletes the attachments from the document and attaches the zipfile to the document.

I can think of a lot of improvements, like setting a flag which means that the attachments already have been zipped, having a user editable field for the zipfilename, or using the date for the zipfilename, or what about an online zipper? Just provide the user with a form on which he can upload a file, have an agent zip the attachment and present the zipped file?

All in all very straightforward I would say! No need for external libraries, tools, etc. It's all done with built-in functionality of the Domino server and the Notes client. Isn't this the reason why we all love Domino?

Jake's Comments:

Thanks Erwin. Great write up.

You may all have noticed that this isn't really a Domino based solution. When we have a web based application the attachments are rarely in the Body field. This is not to say that it can't be made in to one though, as Erwin mentions. The reason I decided to publish Erwin's article is that it is such good food for thought.

I've placed the code in a file you can download from the top left of the page, to make life easier.

About the Author:

Erwin van Hunen is from The Netherlands and currently works as a Lotus Domino Application Architect for Inter Access B.V.