On Wed, 29 Mar 2000, Asim Jalis wrote:
> Asim Jalis wrote:
>
> > Has anyone used Jacl to write Java servlet code? How
> > well does this work? Any experiences or pointers or URL
> > references?
>
> Mo DeJong wrote:
>
> > I have not heard of anyone doing that before, but there is no reason
> > it should not work. Jacl and Tcl Blend are generic interfaces to
> > Java, so you do not need "wrapper" code. Just about anything you can
> > do in Java, can be done in TclJava with ease. A good way to learn
> > how TclJava works is to take some Java code you already wrote and
> > convert it over to TclJava code. If you need any help figuring out
> > how to convert Java code to TclJava code, feel free to post a small
> > code fragment to the list.
>
> I am appending a simple example servlet:
>
> ------------------------------CUT------------------------------
> import java.io.*;
> import javax.servlet.*;
> import javax.servlet.http.*;
>
> public class Hello extends HttpServlet {
> public void doGet (HttpServletRequest request, HttpServletResponse response
> ) throws ServletException, IOException {
> PrintWriter out;
> response.setContentType("text/html");
> out = response.getWriter();
> out.println("<HTML><HEAD><TITLE>Hello</TITLE></HEAD><BODY ");
> out.println("bgcolor=\"#FFFFFF\"><H1> Hello World </H1></BODY></HTML>");
> out.close();
> }
> }
> ------------------------------CUT------------------------------
>
> Notice I have to extend HttpServlet. Based on the TclJava man-page
> (correct me if I am missing something) it does not seem to be possible
> to define or extend a Java class within TclJava.
>
> Is there a way to do this? How? Could you re-write this bit of code in
> TclJava? Or is there some way of organizing the code so that the
> servlet code (the stuff inside doGet) can call Tcl functions which I
> define somewhere else using Tcl language constructs?
>
> Thanks for your help.
>
>
> Asim
Well, yes extending a Java class is one of the things you can not
do with TclJava. For one thing, there is no concept of a "class"
in Tcl. Incr Tcl supports classes but plain Tcl does not. A very
cool project would be to provide a generic interface so that Incr Tcl
classes could extend Java classes. Another cool project would be
to port Incr Tcl over to Jacl (Jacl supports namespaces so it should
not be all that hard).
At any rate, here is a quick rundown of "most" of the things you
would need to do to get this code converted.
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
Would become:
java::import -package java.io ...
java::import -package javax.servlet ...
java::import -package javax.servlet.http ...
The catch here is that you would need to replace ... with the names
of the classes you actually use. There are a couple of reasons for this.
First, it is not possible to query the names of all the classes in
a package using the Java reflection API (yeah, I know that sucks).
Second, it is actually better to only list the classes you use
because you are less likely to have a name clash later on as
the contents of packages are changed.
As for the doGet you could define a Tcl proc like so:
proc doGet { request response } {
$response setContentType "text/html"
set out [$response getWriter]
$out println "<HTML><HEAD><TITLE>Hello</TITLE></HEAD><BODY "
$out println "bgcolor=\"#FFFFFF\"><H1> Hello World </H1></BODY></HTML>"
$out close
}
Ok, so now you would just need to write a "wrapper" (I know, I know
I said you would not need to write a wrapper) for the HttpServlet
class.
import tcl.lang.Interp;
public class HttpServlet_TclWrapper {
Interp interp;
public HttpServlet_TclWrapper(Interp interp) {
this.interp = interp;
}
public void doGet (HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
// eval() the "doGet" Tcl proc. ( I will get back to this in a sec )
}
}
>From your Tcl code you could load up an instance of this class and
tell it to use the interp like so.
set serv [java::new HttpServlet_TclWrapper [java::getinterp]]
I assume you would also need to do something else to "register" it
with a web server.
Now the only bit left is to call Interp.eval() when you need
to process the doGet method. This is tricky because you need
to make sure that your eval() call is thread safe so that
the interp wont get hosed up. The way you do this is to use the
Notifier to add and event to the event queue.
Here is a quick cut and paste from a old paper I
wrote about Tcl Blend and Jacl that covers this.
(http://www.cs.umn.edu/~dejong/tcl/paper.html).
You would want to create an "event wrapper" for your
HttpServlet_TclWrapper class like this.
// File EventProcessor.java
import tcl.lang.ReflectObject;
import tcl.lang.Interp;
...
class EventProcessor extends TclEvent {
String script;
HttpServletRequest request;
HttpServletResponse response;
EventProcessor(String script, HttpServletRequest request,
HttpServletResponse response) {
this.script = script;
this.request = request;
this.response = response;
}
public int processEvent(int flags) {
ReflectObject ref_request = ReflectObject.newInstance(interp,
HttpServletRequest.class,
request);
ReflectObject ref_response = ReflectObject.newInstance(interp,
HttpServletResponse.class,
response);
try {
interp.eval(script + " " + ref_request + " " + ref_response, flags);
} catch (TclException e) {}
return 1;
}
}
Then in your HttpServlet_TclWrapper class you
would want to define the doGet() method like this:
public void doGet (HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
EventProcessor ep = new EventProcessor("doGet", request, response);
interp.getNotifier().queueEvent(ep, TCL.QUEUE_TAIL);
}
The event would then get processed at some later time when the Tcl
interp was ready.
So that "should" be a fairly good roadmap to get you started.
Of course, I just jotted all this code down so I doubt it would
compile and there is some error checking you might want to
take into account.
I have to admit that this whole "put an event into the queue"
system is a little bit too hard to use right now. It is something
that really should be redone for TclJava 1.3. The java::bind
command does this for Bean events but it would be nice to make
it even more generic.
later
Mo DeJong
Red Hat Inc.
----------------------------------------------------------------
The TclJava mailing list is sponsored by Scriptics Corporation.
To subscribe: send mail to [EMAIL PROTECTED]
with the word SUBSCRIBE as the subject.
To unsubscribe: send mail to [EMAIL PROTECTED]
with the word UNSUBSCRIBE as the subject.
To send to the list, send email to '[EMAIL PROTECTED]'.
An archive is available at http://www.mail-archive.com/tcljava@scriptics.com