Forum OpenACS Q&A: Response to A Technical Paper on Java
Try downloading acs-java-4 and give it a spin. You will see what I mean. It's deceptively similar to acs-tcl-4, but once your start debugging, you will realize that you're in a whole different world, and it's not a friendly place.
The first thing that you notice is that error messages such as complilation errors and stacktraces don't correspond to anything in your source files. I found several problems in the workflow package, so I decided that I would try debugging it. I knew that .ajp pages in acs-java are converted from .ajp to .generated.ajp files with the tcl-like macros expanded. Naturally, I assumed the error messages would correspond to the .generated.ajp files. This turned out not to be true. The .generated.ajp files are converted to servlets and then compiled before being executed. So when you want to see what line corresponds to an error, you have to track down the corresponding auto-generated servlet file that corresponds to the url that you accessed. Finding the auto-generated file itself is not easy either. All of the auto-generated files are placed in a working directory with extremely long auto-generated mangled names. Usually,they look something like the following:
_0002fpackages_0002facs_0002dworkflow_0002fwww_0002findex_0002egenerated_0002ejspindex_0002egenerated_jsp_0.java
Multiple versions of the same servlet are left lying around, so make sure you get the latest one.
When you list the working directory with all of the auto-generated servlet files, you end up with a big mess because all of the long file names that are wrapping around in your terminal window.
The net result is that something simple like this:
<%@ include file="/acs.jspi" %> <% ad_page_contract { @author rhs@mit.edu @creation-date 2000-09-18 @cvs-id index.ajp,v 1.8 2001/02/24 15:45:52 deison Exp } -properties { package_name:onevalue context_bar:onevalue site_nodes:multirow } BigDecimal package_id = acs.pkg.getPackageId(); String package_name = [db_string name { select instance_name from apm_packages where package_id = :package_id }]; ContextBar context_bar = new ContextBar(); BigDecimal node_id = acs.request.getSiteNode().getNodeId(); String contextPath = request.getContextPath(); db_multirow site_nodes { select :contextPath || site_node.url(node_id) as url, acs_object.name(object_id) as name from site_nodes where parent_id = :node_id and object_id is not null } ad_return_template %>
Turns into something like this:
package p_00025ckages.acs_0002dworkflow.www; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import javax.servlet.jsp.tagext.*; import java.io.PrintWriter; import java.io.IOException; import java.io.FileInputStream; import java.io.ObjectInputStream; import java.util.Vector; import org.apache.jasper.runtime.*; import java.beans.*; import org.apache.jasper.JasperException; import com.arsdigita.util.*; import com.arsdigita.acs.*; import com.arsdigita.acs.html.*; import com.arsdigita.db.*; import java.util.*; import java.sql.*; import java.math.BigDecimal; import java.io.IOException; import java.io.File; import org.apache.oro.text.perl.*; import org.apache.oro.text.regex.*; import org.apache.turbine.util.mail.Email; public class _0002fpackages_0002facs_0002dworkflow_0002fwww_0002findex_0002egenerated_0002ejspindex_0002egenerated_jsp_0 extends HttpJspBase { static { } public _0002fpackages_0002facs_0002dworkflow_0002fwww_0002findex_0002egenerated_0002ejspindex_0002egenerated_jsp_0( ) { } private static boolean _jspx_inited = false; public final void _jspx_init() throws JasperException { } public void _jspService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { JspFactory _jspxFactory = null; PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; String _value = null; try { if (_jspx_inited == false) { _jspx_init(); _jspx_inited = true; } _jspxFactory = JspFactory.getDefaultFactory(); response.setContentType("text/html;charset=8859_1"); pageContext = _jspxFactory.getPageContext(this, request, response, "/errors.jsp", true, 8192, true); application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(7,4);to=(9,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(9,41);to=(10,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(10,40);to=(11,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(11,45);to=(12,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(12,39);to=(13,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(13,44);to=(14,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(14,41);to=(15,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(15,40);to=(16,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(16,33);to=(17,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(17,47);to=(18,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(18,48);to=(19,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(19,55);to=(20,0)] out.write(" "); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(20,35);to=(22,0)] out.write(" "); // end // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/acs.jspi";from=(22,2);to=(24,0)] PageVariables acs = new PageVariables(); // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/packages/acs-workflow/www/index.generated.jsp";from=(0,31);to=(2,0)] out.write(" "); // end // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/packages/acs-workflow/www/index.generated.jsp";from=(2,2);to=(23,0)] /* Displays the user's task list. @author Lars Pind (lars@pinds.com) @creation-date 13 July 2000 @cvs-id index.ajp,v 1.1 2000/12/01 22:34:51 luke Exp */ HashMap validationBlockResults = new HashMap(); HashMap validationBlockErrors = new HashMap(); HashMap validationBlockDefaultErrors = new HashMap(); if (validationBlockErrors.size() > 0) throw new PageContractException(validationBlockErrors.values()); ContextBar context_bar = new ContextBar(); CallStack __stack = (CallStack)request.getAttribute("com.arsdigita.acs.CallStack"); if (__stack == null) { __stack = new CallStack(); request.setAttribute("com.arsdigita.acs.CallStack", __stack); } __stack.put("context_bar", context_bar); if (request.getAttribute("javax.servlet.include.request_uri") == null) { pageContext.forward(TemplateTranslator.getTemplate(pageContext)); } else { out.flush(); pageContext.include(TemplateTranslator.getTemplate(pageContext)); } // end // HTML // begin [file="/home/nsadmin/tomcat/webapps/acs-java-4/packages/acs-workflow/www/index.generated.jsp";from=(23,2);to=(24,0)] out.write(" "); // end } catch (Exception ex) { if (out.getBufferSize() != 0) out.clearBuffer(); pageContext.handlePageException(ex); } finally { out.flush(); _jspxFactory.releasePageContext(pageContext); } } }You can debug this without any special tools, but it sure is a PIA. If you work on this stuff, it seems that you would have to have some type of visual debugging tool that can quickly resolve the disconnect between your source code and the auto-generated servlet code that is actually executed.
Also, since you must now depend on a visual debugging tool, let's hope you can find a good one. My experience with visual debugging tools is that it's usually faster to use println than to waste your time with those buggy inflexible development environments. That idea of quickly stepping through your code and isolating the problem is a nice one, but ususally you spend all of your time trying to get the visual debugger to work properly.
As far as visual debugger that work with aolserver/tcl, i've heard that tclpro will work, but I wouldn't waste my time with it, as aolserver/tcl is so easy to debug anyway.
And what is special about MVC with regards to servlets? That paradigm can be implemented in tcl as well.