Picking up from after Labbook.May15.txt, it's now 2005.May.17 at 07:44 and I'm ready to start the actual code to convert list of tokens into parsed s-expression using nested MyList structures ... taking a break at 10:36 to handle a personal matter. Resuming at 12:12 ... finished at 13:49, including an XML generator so that after parsing something we can see that it really did parse it (when we use the s-expression printer, the output looks just like the input and we can't prove we didn't just normalize spaces between tokens, but with XML output it's blatantly clear we really did parse it as well as clear that we want to work with nice terse s-expressions instead of horribly verbose XML). Cleaned up test/demo, now it's 14:10. Here's a test run, with the first s-expression canned and the rest typed in by the usr: The canned input string was: "JunkString1" (("FirstName" "Robert")("LastName" "Maas") ("City" "Sunnyvale")) "JunkString1" "JunkString1" "FirstName" "Robert" "LastName" "Maas" "City" "Sunnyvale" (("FirstName" "Robert") ("LastName" "Maas") ("City" "Sunnyvale")) Enter one or more s-expressions(s): (("a")) () "foo" ("whatever" "now" ()) "a" (("a")) () "foo" "foo" "whatever" "now" ("whatever" "now" ()) Next to write the actual test rig for MyHttpApplet, but first a nap. Now 15:04 and it occurs to me that I need to allow [] as well as () to delimit lists on input, to make it easy to include s-expressions as literal string constants in test-rig programs. So I'll do that now ... wait a minute, at 15:32 I realized this is pointless, it's quotemarks, not parens, that are a problem in strings, what was I thinking?? Well some of that work is still correct, and some was wasted, not anything to get really upset about waste of time, compared with the many many days of lost work due to deploytool and J2EE not working. Anyway, switching now to using brackets as stand-ins for quote marks, not as stand-ins for parentheses!! Done at 16:10, here's new demo: The canned input string was: "JunkString1" (("FirstName" [Robert])([LastName] [Maas]) ([City] [Sunnyvale])) (Note that for input only, you can write a string as either "sometext" or [sometext], but on output strings alwasys show as "sometext".) "JunkString1" "JunkString1" "FirstName" "Robert" "LastName" "Maas" "City" "Sunnyvale" (("FirstName" "Robert") ("LastName" "Maas") ("City" "Sunnyvale")) Enter one or more s-expressions(s): ([apple] [pear] [banana]) "apple" "pear" "banana" ("apple" "pear" "banana") Enter one or more s-expressions(s): (([fruit] [apple]) ("animal" "bear")) "a" "fruit" "apple" "animal" "bear" (("fruit" "apple") ("animal" "bear")) "a" "a" *** Had to rush to take shower then catch bus to class for midterm *** Next day, May 18, at 12:39. Last night it occurred to me that my XML for string literals isn't proper. Because the representation of the string is explicitly delimited by quote marks, it should be a property within a non-container tag, rather than between start and end tags of a container tag. The problem is that I need to make up a totally useless name for that tag, such as: Can anybody think of a non-useless name to put there? Alternately I could use a container tag, but omit the quote marks: JunkString1 Would that be proper XML? I can't choose, and it's not important, so I won't bother to fix it either way right now, at 12:44. Break. Resuming work at 16:20, checking some info I found on the net earlier ... OK, I've found that Runtime rt = Runtime.getRuntime(); rt.exec("anyShellCommandString"); runs fine except the output from executing it goes to /dev/null, and I can't even use stdout redirection > outputfile in the command, that's ignored. But I found a trick to get output to a file: Write a shell command file with the stdout redirection in it, and then in the rt.exec simply invoke your favorite shell (such as sh) with the shell command file name as parameter. I also tried System.getenv("HOME"); which is listed in the 1.3.1 API documentation as "depricated", but in fact when I try to run that it throws an exception: Exception in thread "main" java.lang.Error: getenv no longer supported, use properties and -D instead: HOME at java.lang.System.getenv(System.java:677) at T2.main(T2.java:6) But I think I know a simple way for a java program to learn that info, specifically anything that the 'env' system command spews out. Working on testing my idea at 17:39 ... yes it works! Here's the code: Runtime rt = Runtime.getRuntime(); rt.exec("sh envx.sh"); ResourceBundle rb = ResourceBundle.getBundle("env"); Enumeration en = rb.getKeys(); System.out.print("Keys are:"); while (en.hasMoreElements()) { System.out.print(" " + Sexpr1.toSexpr(en.nextElement())); } System.out.println(); String home = rb.getString("HOME"); System.out.println("HOME = " + home); and here is the output: Keys are: "DISPLAY" "HOSTTYPE" "XFILESEARCHPATH" "APPHOME" "BASH_ENV" "RUNLEVEL" "PATH" "JREHOME" "LOGNAME" "SHLVL" "INIT_VERSION" "COLORTERM" "HISTSIZE" "HISTFILESIZE" "ANT_HOME" "XAUTHORITY" "INPUTRC" "SHELL" "PREVLEVEL" "HOSTNAME" "AUTOBOOT" "SESSION_MANAGER" "OSTYPE" "WINDOWID" "MAIL" "LANG" "LD_LIBRARY_PATH" "HOME" "USERNAME" "LINGUAS" "LC_ALL" "J2EE_HOME" "NLSPATH" "GDMSESSION" "USER" "JAVA_HOME" "TERM" "GDM_LANG" "CONSOLE" "BOOT_IMAGE" "_" HOME = /home/rem So now it's 18:04 and I'll take a nap, etc. Now later that evening (May.18) at 21:21, going to see if I can do what I planned back on May.12, namely getting environment info in both JSP and handcoded servlet, and checking what calls are made from the JSP/Servlet, to make sure I know what I need to emulate ... looking for which files to inspect, but they're all gone until I start the J2EE server, doing that now at 21:27, waiting for it to start ... 21:34 it's ready. First I'm trying all the installed applications to find out which are working tonight: - date (jsp) -- completely working, but see also: - date/index2.jsp -- My modified code working. - date/index3.jsp -- Cross-link to doGet method for hello1.java/class works - date/getstuff.jsp -- My modified code working. - hello1 -- Broken, just gives me a directory listing for / which shows original.war and duke.waving.gif, showing / really means public_html/hello1/ The other deployed things that work are either more JSPs, or EJBs, not any working hand-coded HttpServlets. So I'm going to give up comparing JSP environment against direct hand-coded HttpServlet environment. I'll look only at JSP environment and just assume that's the same as it would be with hand-coded servlets. But I'll look at the code in all the examples I can find in source-code (JSP or java) form, to see what kinds of environment calls I might need to handle, such as asking the request object to reveal the session object, or writing data to the output stream within the response object, etc. So starting to look at source code ... bookstore1/ BookDetailsServlet.java getServletContext().getAttribute("bookDB"); throw new UnavailableException("Couldn't get database."); HttpSession session = request.getSession(true); ResourceBundle messages = (ResourceBundle)session.getAttribute("messages"); response.setContentType("text/html"); response.setBufferSize(8192); PrintWriter out = response.getWriter(); out.println("

" + ... response.encodeURL(request.getContextPath() + ... response.encodeURL(request.getContextPath() + "/catalog") + catch (BookNotFoundException ex) { response.resetBuffer(); throw new ServletException(ex); (Those same kinds of method calls are repeated in nearly each *.java file.) hello1/ GreetingServlet.java RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/response"); if (dispatcher != null) dispatcher.include(request, response); So I'm glad I made that scan, because now I know there are actually only a very few features of request/response/session objects that are commonly used, so I won't need to implement much in my fake classes. So now it's 22:23, and I need to install test code to get list of all possible keywords for: getServletContext().getAttribute("..."); // Called from init() // also called from doGet(...) session.getAttribute("messages"); // Called from doGet(...) and I'll need to check what kind of string is generated by code like this: response.encodeURL(request.getContextPath() + "/catalog") So let's do these in sequence, working from the class we're in (HttpServlet) and the classes of the two parameters we have at the start of the Servlet (HttpServletRequest and HttpServletResponse): In class javax.servlet.http.HttpServlet, method getServletContext() is inherited from javax.servlet.GenericServlet, return value is of type javax.servlet.ServletContext, I'll need to check that [#1] in the JSP environment. In that class, getAttribute(String) [[Modem lost connection as it usually does several times per day, need to reconnect to get that info I need at 22:49, this random-modem-crapout has been happening ever since the local phone circuits were switched to digitally encoded ... done and back to where I was looking in API doc at 22:53]], return value is declared as Object, string parameter is supposed to follow fully-qualified rules, such as javax.* etc. getAttributeNames() can be used to get the list of all such names in use in this servlet container, via an Enumeration as the return value there. So I need to write code like this (in a java scriptlet in the JSP acting as a javax.servlet.http.HttpServlet): javax.servlet.ServletContext sc = getServletContext(); (Verify class of actual object I got back) Enumeration en = sc.getAttributeNames(); (usual while loop to println each name) At 23:04, starting to put that code in the JSP I was playing with ... 23:13 have code in the JSP which is not recompiling ... 23:15 it's ready, but got Servlet exception. Oh, when I copied a line of code from elsewhere I forgot to change the name of the variable, fixed and recompiling again ... 23:18 done and this time it worked: Servlet context is org.apache.catalina.core.ApplicationContextFacade@1c2192 Going to list each property in that context: locales javax.servlet.context.tempdir org.apache.catalina.resources org.apache.catalina.WELCOME_FILES org.apache.catalina.jsp_classpath That's not very many, so I'll change the code to actually list the value of each key, done at 23:28, waiting for JSP to recompile ... oops, compiler error, fixed my mistake, recompiling at 23:30 ... oops, another bad line of code: String val = sc.getAttribute(key); I'm so used to properties files which have string values, I forgot that attributes can be *any* Java object, will fix that ... done, 23:32 recompiling ... 23:34 finally working: Going to list each property in that context: * [locales] = [MyLocales@127275] * [javax.servlet.context.tempdir] = [/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/web/da te] * [org.apache.catalina.resources] = [org.apache.naming.resources.ProxyDirContext@187298] * [org.apache.catalina.WELCOME_FILES] = [[Ljava.lang.String;@b7298] * [org.apache.catalina.jsp_classpath] = [/usr/java/j2sdkee1.3/public_html/date/WEB-INF/classes/:/usr/java/j2sd kee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/DateApp1 115343413769Server.jar] OK, that's enough of that for now. The jsp_classpath might be useful to change in my test rig. Now on to the other thing I need to investigate, with new test code, regarding session object and getAttribute on that. My test code already has (from the other day) this code: out.println("** session object" + br + s2 + session + br); HttpSession sess = request.getSession(false); out.println("** sess = request.getSession(false)" + br+ar + sess+br); String sessid = sess.getId(); String sessionid = session.getId(); out.println("session.getId(): " + sessionid + br); out.println(s3+"sess.getId(): " + sessid + br); out.println(s4 + s4 + s3 + s3 + s3 + "(They " + (sessionid.equals(sessid) ? "" : "dis") + "agree.)" + br); String rs = request.getRequestedSessionId(); out.println("* rs = request.getRequestedSessionId()" + br + s4 + s3 + s3 + s2 + ar + rs + br); out.println(s4 + s4 + s3 + s3 + s3 + "(That request was " + (sessionid.equals(rs) ? "" : "not ") + "satisfied.)" + br); which produces this output: ** session object org.apache.catalina.session.StandardSessionFacade@5562b ** sess = request.getSession(false) --> org.apache.catalina.session.StandardSessionFacade@5c30f6 session.getId(): B1D6A4C80382C5A743B0D4E69414B476 sess.getId(): B1D6A4C80382C5A743B0D4E69414B476 (They agree.) * rs = request.getRequestedSessionId() --> B1D6A4C80382C5A743B0D4E69414B476 (That request was satisfied.) so now I need new test code calling session.getAttributeNames(), except this time the enumeration is guaranteed to contain nothing except strings. Copying the code from the other getAttributeNames call (from the other class) and adapting it... done, JSP recompiling at 23:55 ... hmm, no output from that new code except the header, as if the system object had no properties whatsoever. I'll have to debug my test code by setting a couple properties and see if they show up in the output ... lost modem connection again but all I need is the method signature, so rather than going back online I used my reflection utility, which showed this method: 12: public abstract void javax.servlet.http.HttpSession.setAttribute(java.lang.String,java.lang.Object) I wonder why it accepts Object, when they are supposed to always be Strings?? Oh well. Upcasting is safe so I don't care. Done, new code: session.setAttribute("school", "De Anza"); session.setAttribute("city", "Cupertino"); and it works, output from enumeration loop now says: * [school] = [De Anza] * [city] = [Cupertino] One last capability of the servlet environment to test, out.println("* The encoded URL is: " + response.encodeURL(request.getContextPath() + "/catalog")); done, recompling JSP on Thursday May.19 at 00:16 ... done, output: * The encoded URL is: /date/catalog OK, I think I understand how these features work. Next to write a test rig that provides a capability and a pseudo-HttpServlet which makes calls such as found in the sample servlets earlier, but it's bedtime right now, at 00:20, so I'll upload this log file then go to bed.