JavaAgent Exception

I’m quite new to Java, so it is likely my problem is fairly obvious. I am writing a Java Agent that will ultimately take a file attachment from a web form and make a thumbnail for it. I am planning on using Jimi for the image scaling, but can’t seem to get that far.

This is the error I am getting,

NotesException: Notes error: A database handle to a remote database cannot be used by more than one thread. (C:\DOCUME~1******~1\LOCALS~1\Temp\eo67005552tm)

at lotus.domino.local.EmbeddedObject.NextractFile(Native Method)

at lotus.domino.local.EmbeddedObject.extractFile(Unknown Source)

at lotus.domino.local.EmbeddedObject.getInputStream(Unknown Source)

at JavaAgent.NotesMain(JavaAgent.java:43)

at lotus.domino.AgentBase.runNotes(Unknown Source)

at lotus.domino.NotesThread.run(NotesThread.java:218)

And here is my code,

Session session = getSession();

AgentContext agentContext = session.getAgentContext();

Document currentDoc = agentContext.getDocumentContext();

// List all file type items

Vector items = currentDoc.getItems();

for (int i=0; i< items.size(); i++)

{

Item item = (Item) items.elementAt(i);

if (item.getType() == Item.ATTACHMENT)

{

String filenameString = item.getValueString();

EmbeddedObject attachmentObj = currentDoc.getAttachment(filenameString);

InputStream inputStream = attachmentObj.getInputStream();

// I’ll be doing something else in here…

inputStream.close();

attachmentObj.recycle();

}

item.recycle();

}

currentDoc.recycle();

The error happens any time I use getInputStream(), either to set an InputStream variable or send it to a Jimi class. I am able to use the other EmbeddedObject functions, getName, getFileSize. The em********tm file may not be created, otherwise it is deleted quickly, because I never find it (even before I was doing garbage collection).

Subject: JavaAgent Exception

Sam,

The line…

String filenameString = item.getValueString();

…returns the value of the field and I don’t see how this could be the attachment file name. Have you tried inserting System.out.println() statements throughout your code to verify what is going on at each point? You use the Java Debug Console to see the results.

Here is the approach I use to detach multiple files from a rich text field in a doc…

// Set Document doc and String workDir, then…

if (doc == null) {

return;

}

else if (doc.getItemValueString(“fileAttachments”) == null) { // If fileAttachments field is empty, stop further processing.

return;

}

else { // Otherwise, file attachments exist – let’s download them to hard drive.

RichTextItem rtitem = (RichTextItem)doc.getFirstItem(“fileAttachments”);

if (rtitem.getType() == rtitem.RICHTEXT) {

Vector v = rtitem.getEmbeddedObjects();

Enumeration e = v.elements();

while (e.hasMoreElements()) {

EmbeddedObject eo = (EmbeddedObject)e.nextElement();

if (eo.getType() == EmbeddedObject.EMBED_ATTACHMENT) {

eo.extractFile(workDir + eo.getSource());

}

}

}

Ken

Subject: RE: JavaAgent Exception

Thanks for your response.

The getValueString does return the filename, and perhaps a null character. the attachmentObj does contain the attachment from what I can tell. When I print the getName of it, it returns the correct filename, and getFileName returns the corect file size. I stripped out the println commands when I posted since it was just debugging stuff.

Unfortunately your code will not work for me. The attachments are not in a richtext field, but attached to the document itself. Document.getEmbeddedObjects doesn’t return file attachments.

Subject: JavaAgent Exception

Does it work if you run the agent manually from Notes client?Does it work to detach the attachment to disk?

Does it work if you hardcode the name of the attachment?

Do you have additional code in the agent which accesses the same database using another object handle?

Subject: JavaAgent Exception

I’ve done this and I’ve gotten it to work in a WebQuerySave Agent. I get the original code from here and worked off of that: http://www.openntf.org/Projects/codebin/codebin.nsf/0/90A96A34D110344386257035005FC39D

I’m trying now to make it work on more than just one image if the document has multiple image attachments. I think I’m stuck making multiple RT fields for the thumbs, one per image.

Let me know if this helps.

//ImageResizeToStream.java

import lotus.domino.Session;

import lotus.domino.Stream;

import com.sun.image.codec.jpeg.JPEGImageDecoder;

import com.sun.image.codec.jpeg.JPEGCodec;

import com.sun.image.codec.jpeg.ImageFormatException;

import java.awt.image.FilteredImageSource;

import java.io.ByteArrayOutputStream;

import java.io.InputStream;

import com.sun.jimi.core.filters.AreaAverageScaleFilter;

import com.sun.jimi.core.Jimi;

import java.awt.Image;

//import gnu.regexp;

public class ImageResizeToStream

{

private final boolean DEBUG = true;



public Stream createResizedImage( Session session, InputStream is, int resizedWidth, int resizedHeight) throws Exception

{

	try

	{

		// Get the new image into the decoder

		JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(is);

 		// and decode

		Image image = decoder.decodeAsBufferedImage();

		

			FilteredImageSource filteredImage = new FilteredImageSource (image.getSource(), new AreaAverageScaleFilter (resizedWidth, resizedHeight));

			ByteArrayOutputStream  bout = new  ByteArrayOutputStream();

		Jimi.putImage( "image/jpeg",  filteredImage, bout);

		

		// convert bytestream to bytearray 

		byte [] imageByteArray = bout.toByteArray();	

		

		// Populate a NotesStream with the data 

		Stream stream = session.createStream(); 

		stream.write (imageByteArray);

		return stream; 

	}

	catch ( ImageFormatException ife ) 

	{

		if ( DEBUG ) ife.printStackTrace(); 

	}	

	catch ( Exception e )

	{

		e.printStackTrace();

	}

	return null; 

}

}

//WQS_ImageUpload.java

import lotus.domino.*;

import java.io.PrintWriter;

import java.util.Vector;

public class WQS_ImageUpload extends AgentBase

{

private final boolean DEBUG = true;



private final int THUMBPHOTOWIDTH = 60;

private final int THUMBPHOTOHEIGHT = 60;

private final String RTFIELD = "PhotoThumb";

private final String IMAGENAMEFIELD = "ThumbImageName";

private final String HASTHUMBFIELD = "HasThumb";



private Session session;

private AgentContext agentContext;

private Database db;

private Document doc;

private EmbeddedObject obj;

private String serverName;

private String dbName;

private String docid;



private Stream thumbPhotoStream;



private MIMEEntity photoThumb;



private Vector fieldUpdates = new Vector();



public void NotesMain()

{

	try

	{

		if ( DEBUG ) Utils.debug ( "|");

		if ( DEBUG ) Utils.debug ( "/-------------------------------------------------" );

		if ( DEBUG ) Utils.debug ( "imageUpload agent started");

		if ( DEBUG ) Utils.debug ( "|");

		

		// Get the in-memory document

		session = getSession();

		agentContext = session.getAgentContext();

		db = agentContext.getCurrentDatabase();

		doc = agentContext.getDocumentContext();

		

		// Get the image file from the in-memory document

		Item file = doc.getFirstItem("$FILE");

		if (file != null)

		{

			String fileName = cleanStringBuffer(file.getValueString());

			

			Vector v = null;

			Session session = getSession();



			final String fileexts = ".jpg .jpeg";

			final String MACRO = "@Contains(\"" + fileName.toUpperCase() + "\"; @Explode(\"" + fileexts.toUpperCase() + "\";\" \"))";

			if ( DEBUG ) Utils.debug(MACRO);

			boolean hasJPEG = false;

			try

			{

				v = session.evaluate(MACRO);

				hasJPEG = (((Double)v.firstElement()).doubleValue() > 0) ? true : false;

			}

			catch(Exception e)

			{

				e.printStackTrace();

			}

			

			// This is work around because getting Body calling MIMEEntity.getMIMEEntity("Body") doesn't throw an error but

			// doesn't write the image out. Could be something to do with headers but haven't investigated further

//			doc.removeItem(RTFIELD);

			

			if (hasJPEG)

			{

				obj = doc.getAttachment(fileName);

				

				ImageResizeToStream irts = new ImageResizeToStream();

	

				// Call the image sizing method of the image resize class here, pass it the obj and the width, should return domino.Stream

				thumbPhotoStream = irts.createResizedImage( session, obj.getInputStream(), THUMBPHOTOWIDTH, THUMBPHOTOHEIGHT);

				

				// This is work around because getting Body calling MIMEEntity.getMIMEEntity("Body") doesn't throw an error but

				// doesn't write the image out. Could be something to do with headers but haven't investigated further

				doc.removeItem(RTFIELD);

				

				// Do not convert MIME to rich text

				session.setConvertMIME(false);

				

				// Create the mime entities and set their contents

				photoThumb = doc.createMIMEEntity(RTFIELD);

	

				photoThumb.setContentFromBytes( thumbPhotoStream , "image/jpeg", MIMEEntity.ENC_IDENTITY_BINARY );

				

				// Close down the streams

				thumbPhotoStream.close();

				

				session.setConvertMIME(true);

				

				// Create URL to redirect back to document

				serverName = doc.getItemValueString("server_name");

				dbName = db.getFileName();

			

				fieldUpdates.addElement ( new String[] { IMAGENAMEFIELD, fileName  } );

				fieldUpdates.addElement ( new String[] { HASTHUMBFIELD, "Yes"  } );

	 			

	 			DocUtilities.updateDocument ( doc, fieldUpdates );

// doc.save();

				// Remove the obj

// obj.remove();

			}

			else

			{

				if ( DEBUG ) Utils.debug("Photo is wrong type");

				doc.removeItem(RTFIELD);

				doc.removeItem(IMAGENAMEFIELD);

				doc.removeItem(HASTHUMBFIELD);

				doc.save();

			}

		}

		else

		{

			if ( DEBUG ) Utils.debug("Photo not found");

			doc.removeItem(RTFIELD);

			doc.removeItem(IMAGENAMEFIELD);

			doc.removeItem(HASTHUMBFIELD);

			doc.save();

		}

	}

	catch ( NotesException ne )

	{

		ne.printStackTrace();

	}

	catch( Exception e)

	{

		e.printStackTrace();

	}

	finally

	{

		if ( DEBUG ) Utils.debug ( "|");

		if ( DEBUG ) Utils.debug ( "imageUpload agent finished");

		if ( DEBUG ) Utils.debug ( "-------------------------------------------------/" );

		if ( DEBUG ) Utils.debug ( "|");

	}

		

}

private static String cleanStringBuffer(String target)

{

	StringBuffer buf = new StringBuffer();

	for(int n=0; n<target.length(); n++)

	{

		char c = target.charAt(n);

		if ((byte)c == 0)

			return buf.toString();

		else

			buf.append(c);

	}

	return buf.toString();

}

}