Redirect a user and log movement using a servlet
Last week I trod old ground and spoke about how to get ready to create a servlet for the first time. The obvious carry-on from this is to write an actual servlet. That's what I'm going to do now. The way in which I want to try and do this is that the code I show is actually of some use. All too many "how to write a servlet" type articles end up with a reader thinking "and!?". Hopefully not with this one. If you find this is still the case after reading this, be patient, the next article has an even more useful example.
What the servlet does:
Sat in a meeting recently, the idea of having adverts on an intranet homepage was brought up. Not for anything commercial, just for other parts of the intranet. Nothing special in that. However I got thinking about how this would be a great chance to use a servlet. With it we can redirect the user and log the movement in a database so that the boss can see who and where and what is being clicked. Maybe even a report or two. After all, they like that kind of stuff, don't they.
Using a servlet means that, if this is going to be something used heavily, the server has a lighter load. Servlets are loaded in to memory when they are first run. Conversely, Agents have to loaded in to memory each time they run. Another factor against using an Agent is that, for something like this particular application, there is no rightful home for the code. If you find yourself creating a database just to hold an Agent then maybe it's time to be thinking about using servlets instead.
The Code:
What I don't want to do here is just paste in the whole of the code used. Not that there's a lot of it, just that that doesn't really help anybody. If you want to see the code (you'll have to at some point) then you can open the attached Java file in any Java IDE or a text editor. Let's just look at the important parts.
For all servlets there are two important objects that we always use. The Request (req) and the Response (res) which are initialised for us in the following which is the main class of the servlet and gets called straightaway:
public void service(HttpServletRequest req, HttpServletResponse res)
These two objects have some properties and methods that make life very easy for us. Within the class I made use of the following lines:
1. Stripping parameters out of the requesting URL would normally be a messy affair. Not with servlets, we can use the getParameter() method of the Request object.
String goToURI = req.getParameter("location");
2. If an error occurs we can easily return an error 500 to the browser that is formatted as we normally expect. For example, if the above parameter is missing:if (goToURI == null ) {
res.sendError(res.SC_INTERNAL_SERVER_ERROR, "Error - Location paramater missing!");
}
3. Finally, when we have the location that we want to go to we can send that path to the browser using the sendRedirect() method of the Response object:
res.sendRedirect( goToURI );
How much easier can it get!?
Creating the Domino document isn't quite so straight-forward. In three easy steps it is:
1. Create a new Notes thread, initialise it and create a new session object.
NotesThread nThread = new NotesThread();
nThread.sinitThread();
Session s = NotesFactory.createSession();
2. Open the database, create a document, add the values and save it.
Database db = s.getDatabase( "", "apps/redirect.nsf" );
Document doc = db.createDocument();
doc.replaceItemValue( "Form", "Log" );
doc.replaceItemValue( "Date", df.format( now ) );
doc.replaceItemValue( "Path", goToURI );
doc.save( true );
3. Finally, close the Notes thread.
nThread.stermThread();
Okay, so it's not quite as simple as that. In the above snippets I've missed out all the important try, catch and finally clauses. The way this works should be obvious if you look at the code. Once you get the hang of the skeleton code needed for a servlet you can really go to town. There are many things you can do in servlets that you'd be hard pushed to do with any other technology available so readily.
If you want to get really carried away you could go the whole hog and use just servlets to display your site on the internet. Doing this mean that you can do whatever you like with your HTML without Domino dictating how it's formatted. Now there's a dream....
Trying it out:
If you want to try it out download the example database in to a directory called "apps" on your server and place the LogRedirect.class file in to the server's servlet directory. Open the database and find the homepage. There are instructions and sample links on there. Give it a go. Any problems, let me know.....
Few More Tips
I got the example in this article working pretty quickly after looking over the information on setting up the server to run servlets. One specific note for anyone who already has their server ready enabled for servlets. Don't forget to restart the HTTP task to load in the servlet.
Great job as usual Jake.
Reply
Re: Few More Tips
Hey Jorge,
Thanks for the feedback - it's always good to hear that things are actually working out there in the field.
Not sure what you mean though about having to restart the HTTP task. You only need to do this if you make any changes to the servlet. Otherwise the Servlet Manager will load the class file when it's first requested.
Is that not the case?
Jake -codestore
Reply
Show the rest of this thread
Notes thread creation..
You're creating and destroying a Notes thread for every request - how much overhead does this cause? Is it noticeable under load?
I know previously when I played around with Servlets (it's been awhile now) I tried creating the thread during servlet startup and only destroying in when the servlet was unloaded, however this wasn't very stable. Later I found using CORBA (and only initialising the Notes connection on startup) was quite stable - however CORBA isn't as efficient as using the native calls.
I might have to play around with it again.
Reply
Re: Notes thread creation..
Hmm, good question. The answer to which is that I have no idea.
My Java/Servlet knowledge is still at the "if I get it to work I'm happy" stage. The ins and outs of performance etc come later.
Any evidence you have or ideas for improvement are gratefully received.
Jake -codestore
Reply
Show the rest of this thread
Thanks
Just to say thanks for the help. I managed to write my first servlet because of your 2 articles. I noticed R6 will make it easier to pass all site urls through a servlet first (using URL substition -web site rules).
I could only get the current user (not the server running the servlet) using the request property getRemoteUser() as long I was using session based authentication, any other ideas ?
Reply
Re: Thanks
Cheers Mark. Good to know that somebody else has taken the plunge...
Hmmm, security/authentication. Got to admit I've been avoiding this issue for the time being. We're both at the same point in terms of servlet knowledge by the sounds of it.
One good place for questions is the [<a href="http://www.looseleaf.net/Looseleaf/Forum.nsf">Looseleaf Forum</a>]. If Bob Balaban can't answer it then you're doomed....
Jake -codestore.net
Reply
Servlets - and, how's it going?
Jake - what's news? Any word on the information I provided to you about displaying views using XML/XSL?
Also, I was reading this:
---> Sat in a meeting recently, the idea of having adverts on an intranet homepage was brought up. Not for anything commercial, just for other parts of the intranet. Nothing special in that. However I got thinking about how this would be a great chance to use a servlet. <---
I have a solution that uses neither an agent or a servlet, and works really well. As far as I'm concerned it's the best Domino-based ad serving / tracking technique I've seen. You can see it in action on my site at http://www.prorec.com.
Let me know if you are interested in learning about it.
Hope all is well with you.
Rip Rowan
Reply
Lotus Script version
Hi,
Here´s an example of how the same thing can be coded using a Lotus Script agent.
Basically this example code works on some documents that contains the redirect-url stored in a field. The documents are also used for logging hit information for each url.
A view displays the documents and generates the urls (... redirect?OpenAgent&url=http://www.lotus.com) that when clicked activates the agent. The agent also checks if the same IP is repeatingly hitting the same link, if so only 1 hit per hour is counted.
/Leif
========= CODE STARTS ====================
' This agent is run when a link is clicked in the TopLinks form (see the form in action at http://www.just-in-mind.net/toplinks.nsf/toplinks) ' The agent saves hit information and redirects the user to the selected url
Sub Initialize On Error Goto ErrH 'Variable Declarations Dim session As New NotesSession Dim db As NotesDatabase Dim view As NotesView Dim dc As NotesDocumentCollection Dim docContext As NotesDocument Dim docLink As NotesDocument Dim referenceDateTime As New NotesDateTime( "01/01/2002" ) Dim hitDateTime As New NotesDateTime( "Today" ) Dim linkURL As String Dim secs As Long Dim days As Integer 'Variable Initialization Set docContext = session.DocumentContext linkURL = GetParameter(docContext.Query_String_Decoded(0), "url") Set db = session.CurrentDatabase Set view = db.GetView("LinksURL") Set dc = view.GetAllDocumentsByKey(linkURL, True) 'Looping all matching Link documents Set docLink = dc.GetFirstDocument 'check if the same IP is hitting the same link repeatedly - if so, don´t save hit info Dim DateNow As Variant Dim diffDouble1 As Double Dim diffDouble2 As Double DateNow = Now If docContext.Remote_Addr(0) = docLink.Remote_Addr(0) Then diffDouble1 = Round(DateNow - docLink.LastModified, 4) diffDouble2 = 0.02 If diffDouble1 < diffDouble2 Then Print "[" & linkURL & "]" Exit Sub End If End If 'saving Hit info While Not docLink Is Nothing docLink.Hits = docLink.Hits(0) + 1 secs = hitDateTime.TimeDifference(referenceDateTime) days = Int( secs / 86400 ) docLink.DateScore = docLink.DateScore(0) + days docLink.Remote_Addr = docContext.Remote_Addr(0) docLink.Remote_User = docContext.Remote_User(0) Call docLink.Save(False, False) Set docLink = dc.GetNextDocument(docLink) Wend 'Redirecting user to selected URL Print "[" & linkURL & "]" Exit Sub ErrH: Print "Error " & Str(Err) & ": " & Error$ & " in redirect agent at line: " &Str(Erl) & " Agent run by: " & session.EffectiveUsername End Sub
Function GetParameter(queryString As String, paramName As String) As String On Error Goto ErrH Dim v As Variant v = Evaluate ({@Middle("&} & queryString & {&";"&} & paramName & {=";"&")}) GetParameter = v(0) Exit Function ErrH: Print "Error " & Str(Err) & ": " & Error$ & " in GetParameter function in agent redirect at line: " &Str(Erl) End Function
============= CODE ENDS ======================
Reply
redirecting a servlet
Great article on the Servlet redirect!
I want to have each of my webpages on servlets and I'm having difficulty...any help would be appreciated!
david http://www.concreteforever.com
Reply
Method in the called servlet
In case the location parameter contains an url of another servlet (not of a HTML page or a virtual host) do NOT forget to put in the called (slave) servlet the doGet() method, otherwise the sendRedirect() WILL NOT WORK. One can invoke "doGet" of the slave servlet only. The doPost doesn't work.
Reply