Technote 1222807: Known limitations of Notes and Domino 7.x via the Lotus Domino Support RSS feed.
Month: November 2005
Rumours of the demise of Notes keeps circulating – now customers are calling us asking whether it is true!!
At the office we have received two calls from different customers asking to the rumours that are circulating about the future demise of Lotus Notes. Apparently the customers have been contacted by Microsoft shops asking them whether they really want to bet on a loosing platform that IBM plans to stop investing in after 2007!!
Who starts these rumours? Well I guess we know but how can they get away with it?
I really hope IBM will rise to the challenge and with BIG WORDS in the printed press clearly make the point that Lotus Notes is here to stay!
Creating a download tracker for Domino
function displayServletCode() {
var e = document.getElementById(‘servlet_code’);
e.style.visibility=’visible’;
e.style.display=’block’;
}
When doing a download tracker for binary content there is some issues that must be addressed – one is the MIME type of the file being downloaded. The MIME type determines how the calling browser determines what to do with the response sent by the download tracker. Since the main content being downloaded is going to be images I need to change the MIME type since the browser would otherwise simply display the image. The easy solution is to set the MIME type to application/octet-stream since it will cause the browser to ask where to save the file.
Another obstacle when handling binary data from an agent in Domino is that the default agent output you can obtain from the AgentBase class in Domino is a java.io.PrintWriter. PrintWriter is for character data and therefore not of much use to me.
You obtain the agent output writer by using the getAgentOutput() method of the AgentBase class from which all agents inherit:
import lotus.domino.*;
import java.io.PrintWriter;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
PrintWriter pw = this.getAgentOutput();
} catch(Exception e) {
e.printStackTrace();
}
}
}
The getAgentOutput()-method is the only method to agent output which is discussed in the Domino 6.5.x help database. As mentioned above a PrintWriter isn’t of much use to me – what I really needed was a way to obtain a java.io.OutputStream implementation. Although not mentioned in the documentation I thought Lotus might have added a way to get a such so I wrote an agent to peek at the available methods as reported by the JVM using reflection:
import lotus.domino.*;
import java.io.PrintWriter;
import java.lang.reflect.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Method[] methods = this.getClass().getMethods();
for (int i=0; i<methods.length; i++) {
// get info about the method
Class[] param = methods[i].getParameterTypes();
Class rt = methods[i].getReturnType();
Class[] exceptions = methods[i].getExceptionTypes();
int mod = methods[i].getModifiers();
System.out.print(Modifier.toString(mod));
if (rt.equals(Void.class)) {
System.out.print(" void ");
} else {
System.out.print(" " + rt.getName() + " ");
}
System.out.print(methods[i].getName());
System.out.print("(");
for (int j=0; j<param.length; j++) {
if (j>0) System.out.print(", ");
System.out.print(param[j].getName());
}
System.out.print(")");
for (int j=0; j<exceptions.length; j++) {
if (j>0) System.out.print(", ");
System.out.print(exceptions[j].getName());
}
System.out.println(";");
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
As one might have guessed there is a method called getAgentOutputStream() (highlighted in bold) that returns an OutputStream as shown in the snippet below:
public void NotesMain(); public final void startup(lotus.domino.AgentInfo); public final void runNotes()lotus.domino.NotesException; public lotus.domino.Session getSession(); public static lotus.domino.Session getAgentSession(); public boolean isRestricted(); public java.io.PrintWriter getAgentOutput(); public java.io.OutputStream getAgentOutputStream(); public void setDebug(boolean); public void setTrace(boolean); ... ...
Well this was great so I went ahead and coded the actual agent. Getting at the correct document and attachment based on supplied parameters is straight forward using the Domino Java classes. Once I had a hold on the correct attachment as an EmbeddedObject object I used the getInputStream() method to get an InputStream for the attachment. Until this point all is well and good.
From here on it should be quite simple to set the MIME type via the Content-Type HTTP header and read the bytes from the InputStream and writing them to the OutputStream. Or so I thought…
import lotus.domino.*;
import java.io.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
EmbeddedObject o = null;
// code to get at the correct attachment as an EmbeddedObject
// object has been left out
// get output stream and set mime type
OutputStream agent_out = this.getAgentOutputStream();
agent_out.write("Content-Type: application/octet-streamn".getBytes());
// get an input stream for the attachment
InputStream o_in = o.getInputStream();
// write bytes from input stream to output stream
byte[] bytes = new byte[1];
while (o_in.read(bytes) > -1) {
agent_out.write(bytes);
}
// flush and close
agent_out.flush();
agent_out.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}
While the above code compiles and run just fine there is a problem. For some reason I can’t figure out not all the bytes actually reach the browser. Substituting the OutputStream from Domino (agent_out) with a FileOutputStream I can write the attachment to disk just fine so reading and writing is well. The problem must lie with the Domino OutputStream.
Well I’ll save you more ramblings about my debugging attempts but after a LOT of troubleshooting I ended up rewriting the code as a servlet. Once I ported the above code to a servlet it works like a charm when running it from Tomcat (click here to display the code).
This just strengthened my observation that the problem was with the Domino OutputStream implementation. Again using reflection I could find out exactly which kind of OutputStream Lotus was using:
...
// get output stream and set mime type
OutputStream agent_out = this.getAgentOutputStream();
System.out.println(agent_out.getClass().getName());
Class parent = agent_out.getClass().getSuperclass();
while (null != parent) {
System.out.println(parent.getName());
parent = parent.getSuperclass();
}
...
The result is a PrintOutputStream as shown by the result below:
java.io.PrintStream java.io.FilterOutputStream java.io.OutputStream java.lang.Object
A java.io.PrintStream will use the default encoding when printing characters so it might be because of this my output data gets corrupted.
Conclusion
Well while the solution using a servlet works it isn’t perfect since it is so much easier to configure an agent than a servlet. Looking at the bright side a servlet provided superiour performance so it isn’t so bad I guess.
To summarize I was happy when I found the getAgentOutputStream() method but was equally disapointed when I found out that it didn’t work. To be fair I don’t know whether it is my code or whether it is something in the obtained OutputStream that teases me. I just hope the above will save someone else from spending precious time fiddeling around with binary data from a Domino web agent and that they will go directly to the servlet.
Firefox 1.5 RC2 – I took the plunge…
Well the overall design haven’t changed much – actually the only thing I have noticed so far is that the layout of the “Options…” dialog now has the selectors on top instead of on the right. The display of web pages seems to render faster than in Firefox 1.0.7. Apart from this there are some smaller changes to the available preferences. Check out the release notes for information on all changes.
On the downside there are some extensions that doesn’t work with Firefox 1.5. Of the extensions I have installed the following doesn’t work with 1.5RC2:
- Live HTTP Headers
- Greasemonkey
- JavaScript debugger
The fact that the Live HTTP Headers extension doesn’t work could make me switch back since I use that one a lot in my daily work. As for the JavaScript debugger and Greasemonkey I might be able to live without them for the time being.
Apart from the extensions I have had no bad experiences with it so far so happy days…
Re: Domino 7 web services woes
Cool! I just saw that I have received an e-mail from Torben Bang with some C API code to get at the LotusScript for the web services in a Domino 7 database. I haven’t had a chance to look at the code yet but it sure sounds promising. Thanks!!
Domino 7 web services woes
I really want to expand LotusScript.doc so it can document web services in Domino 7 written in LotusScript. For all the other design elements (forms, views, agents etc.) I can get the LotusScript source code via DXL but this isn’t possible for web services. The DXL only contains a number of elements containing something that looks like Base64 encoded data (<rawitemdata type=’14’>-elements).
I noticed however that the design element itself has a $FILE item with an attachment called %%webserviceresource%%.jar. Guessing that the JAR-file contained the code I tried detaching it and expanding the JAR-file via LotusScript.
Sub Initialize
Dim session As New NotesSession
Dim db As NotesDatabase
Dim doc As NotesDocument
Dim e As Variant
Set db = session.CurrentDatabase
Set doc = db.GetDocumentByUNID("239E4CB31E6F407FC12570A00049AE3A")
Set e = doc.GetAttachment("%%webserviceresource%%.jar")
Call e.ExtractFile("d:lekkim.jar")
End Sub
But no. The JAR-file only contains a WSDL document a property-file and some binary stuff (see below to a directory listing).
I also tried decoding the Base64 encoded data from the DXL document and I found something that looks like my web service LotusScript code. I removed a header of some sort with some non-ASCII characters from the listing below.
'++LotusScript Development Environment:2:5:(Options):0:74 Option Public Option Explicit '++LotusScript Development Environment:2:5:(Forward):0:1 Declare Public Class Lekkim '++LotusScript Development Environment:2:5:(Declarations):0:10 Public Class Lekkim Public Function GetName(user As String) As String End Function End Class
The above is of cause parsable but it would be easier if I would simply get at the code.
If anyone knows how to get at the LotusScript of a web service without decoding the Base64 data from the DXL please let me know. Thanks.
LotusScript.doc well received
As you might know LotusScript.doc has been released and I’m very pleased that I’m seeing a fair number of downloads without any promotion. Very encouraging.
Once the article in The VIEW is out I expect it to pick up further.
My personal experience after using LotusScript.doc in production for internal code and for customer development for a couple of months is very good. Once all projects is automatically being documented developers start adding more and more code comments which further enhances the benefit. I have even had developers come up to me and say how they started using code from other projects. Sweet.
How I would love if IBM Lotus would promote OOP in LotusScript
In the Lotus Support RSS feed I saw a technote about what to do if the you need an array with an index larger than an Integer (32767). Their suggestion is to use a List with string keys!! A List!!
Why not promote the OO features of LotusScript and provide an ArrayWrapper class that simply handles multiple arrays internally and a Long for the counter? I know it would have limitations such as the fact that you cannot use it in Forall statements but still… An object would be so much more elegant. I know OOP is more advanced but if you need such large arrays you really should know what you are doing.
I’m baffled – why not use the opportunity?
Technote 1221020: How to use a list to get around the Array size limit
LotusScript.doc Lotusphere submission
My abstract submission for a Lotusphere 2006 session about LotusScript.doc was not accepted. I just received an e-mail from the track owner. Major bummer since I think it would have been a great session and a good venue to promote code documentation and object oriented design and development…
I will have to cry myself to sleep… 🙁