Picking up from after Labbook.May12.txt, it's now May.15 Early in the morning (last night) while having trouble sleeping, I came up with an idea: Runtime checking of a class against an interface, not the case of print/println I already did, but now for HttpServletRequest and HttpServletResponse. So then I can run a Servlet which has parameters of type Object but which does runtime checking to make sure they are really suitable for treating as if HttpServletRequest and HttpServletResponse respectively. If the Servlet is running as a J2EE servlet application, then it really will have parameters of that type. But if it's running under a swing or CGI conversion rig, it'll have fake objects which act just like they are HttpServletRequest or HttpServletResponse but in fact they are my own hand-crafted classes where I can create the objects from scratch. (I haven't been able to find any public constructors for HttpServletRequest and HttpServletResponse, so I have no way to create them on Linux where I have no way to run a Servlet.) So during the day time May.15 I wrote CompareIntCls.java which gets the list of methods from an interface and a class, sorts each, and collates them to produce three lists: - Those in the interface but not the class (violations of the class implementing the protocol); - Those in both the interface and the class, indicating correct implementation of the interface but with 'throws' exceptions not yet compared, and return type not yet compared (maybe I should do that, and signal an exception if they aren't compatible?), and maybe other subtle properties (public/private, static/instance) that need checking. - Those in the class but not the interface (indicating that I might have written worthless code, if this is one of my minimal fake substitutes for HttpServletRequest or HttpServletResponse), but to be expected with an actual live HttpServletRequest or HttpServletResponse tested against my very minimal interface spec. Then I uploaded that file to show to the world, and updated my JavaClass WebSite to better index the various files I've uploaded. It's now 23:25, past my best bedtime, so I'll do just a little bit more tonight. I think I'll try to deploy the hello1 application, which consists of two HttpServlets. Now 23:28 as I start the J2EE server ... done at 23:35, next running ant ... done at 23:40, next starting deploytool ... done at 23:49, next starting to adapt tutorial instructions to guess what needs to be done for hello1 ... past midnight, got new application named and got past intro screen of new web component, now Monday May.16 00:12, now let's guess what to do next ... finished adding the web component at 00:36, what's next? I'll skip step 8 (table 10-2) because I have no idea where that's located in deploytool, and I'll skip 9 thru 12 because they aren't applicable to hello1. At 00:42, moving ahead with step 13, context root ... at 00:46 that was done and I saved and started deployment, at 00:48 it was done asking me to confirm which application to deploy, at 00:50 it showed first progress (contacted server), deployment done at 01:03 and I clicked OK button, 01:04 it finished refreshing main screen and I went to Netscape, 01:05 I was able to guess at the URL and entered it, at 01:08 it finally put up the greeting screen, I typed my name, clicked submit, but instead of giving me the response form it gave me the original greeting form again. Half-broken! Anyway, total time = 1:18 to configure it + 0:17 to deploy + 0:05 to run it to where it shows the initial greeting screen = 1:40 grand total. Now let me see if I can edit the source, recompile it, manually copy the class file to the system area, and refresh screen, to effect a change in that greeting form ... did edit&recompile, now looking around, I see no isolated class files on system java area, but I see three jar files associated with this application: /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/ hello1App1116255081029.jar hello1App1116255123405Server.jar hello1AppClient.jar I assume I would need to update the contents of at least one of those, but which one? The other day I wrote come code to explore JAR files using the API in java.util.jar.JarFile and java.util.zip.ZipEntry, and I should be able to configure it to look into these JAR files... first jar file doesn't have any regular class files, second ditto, third ditto, so I wonder where the server is keeping the two class files, one of which actually was run to make the initial greeting form? Bedtime at 01:55 May.16 07:15 PDT, half awake, ready to resume. I did a re-load of the Web page, no good, not getting the change I made, so it's not getting the class file directly from the build directory at runtime, it has that copied to some system place as I always assumed. So I'm curious whether there are *ever* files within those jar files on repository? The ones for hello1 are all very small, about 4k, but some are larger: -rw-rw-r-- 1 15600 Apr 26 15:59 conv2App1114556343819Server.jar -rw-rw-r-- 1 11957 Apr 13 18:19 converterAppClient.jar -rw-rw-r-- 1 18632 Apr 13 18:19 converterApp1113441343351Server.jar (those times are GMT) so let me adapt my jar-examination program to see what's in them... These files within JAR file: conv2App1114556343819Server.jar: Conv2.class Conv2Home.class Conv2Bean.class Conv2Bean_EJBObjectImpl.class Conv2Bean_RemoteHomeImpl.class _Conv2Home_Stub.class _Conv2Bean_RemoteHomeImpl_Tie.class _Conv2_Stub.class _Conv2Bean_EJBObjectImpl_Tie.class These files within JAR file: converterAppClient.jar: Converter.class ConverterBean.class ConverterHome.class ConverterClient.class _ConverterHome_Stub.class _Converter_Stub.class These files within JAR file: converterApp1113441343351Server.jar: Converter.class ConverterBean.class ConverterHome.class ConverterClient.class ConverterBean_RemoteHomeImpl.class ConverterBean_EJBObjectImpl.class _ConverterHome_Stub.class _ConverterBean_RemoteHomeImpl_Tie.class _Converter_Stub.class _ConverterBean_EJBObjectImpl_Tie.class Summary, only the applications which are EJBs use such files. Looking elsewhere for copy of class files for hello1 ... /home/rem/TmpDowned/TestEE/j2eetutorial/examples/build/web/hello1/ has a copy of GreetingServlet.class, so I renamed that out of the way and copied the new version in its place, and had Netscape reload the Web page, no change, still the original version. So I have no idea where the old version is cached that I might update it. So let's try deploytool "Update files" to see whether that works any better than it did with the other application (where it said nothing has changed so it refused to update anything)... first I got rid of the copy of the updated class file, and renamed the old version back in place, so as to avoid confusing deploytool. Next, at 08:18, to ask deploytool to update files ... at 08:22 it says it updated the file, so I saved it and will now try to deploy again ... at 08:27 it showed first progress (Contacted Server) ... at 08:33 it's done, I'll press OK button now ... done. Now at 08:38 I'll have Netscape reload the page ... A Servlet Exception Has Occurred Exception Report: javax.servlet.ServletException: Error allocating a servlet instance at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:606) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:215) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2314) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:368) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:163) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.connector.http.HttpProcessor.process(HttpProcessor.java:995) at org.apache.catalina.connector.http.HttpProcessor.run(HttpProcessor.java:1088) at java.lang.Thread.run(Thread.java:484) Root Cause: java.lang.ClassFormatError: GreetingServlet (Bad magic number) at java.lang.ClassLoader.defineClass0(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:486) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:111) at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:1484) at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:851) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1230) at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1113) at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:790) at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:602) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:215) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2314) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.authenticator.SingleSignOn.invoke(SingleSignOn.java:368) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:564) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:163) at org.apache.catalina.core.StandardPipeline.invokeNext(StandardPipeline.java:566) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:472) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:943) at org.apache.catalina.connector.http.HttpProcessor.process(HttpProcessor.java:995) at org.apache.catalina.connector.http.HttpProcessor.run(HttpProcessor.java:1088) at java.lang.Thread.run(Thread.java:484) Summary: It's impossible to modify a J2EE application and deploy it again. The only legitimate thing that can be done is to rename the folder containing those files, configure a whole new application using those renamed files (which takes 1.5 to 6 hours or maybe even longer), and deploy the new application, which takes one hour 40 minutes even for the most simple "hello1" application. So now it's time to get working on my multi-UI stuff so that I can use a simple GUI interface to debug the application, with a turnaround time of two minutes instead of two-to-six hours each time I change one line of code and want to test it. Well, let me first try a couple other ideas. First, I've undeployed the hello1 application, and will try to deploy it again, hoping whatever was confused will be fixed ... OK, past the confirmation of what application to deploy at 09:21 ... finished at 09:28 and clicked OK button, now to have Netscape reload page ... same error as last time: A Servlet Exception Has Occurred Exception Report: javax.servlet.ServletException: Error allocating a servlet instance at org.apache.catalina.core.StandardWrapper.allocate(StandardWrapper.java:606) ... So let me go back to the hack whereby I have a JSP as the application but patch it in-place to directly call a HttpServlet.doGet() method, first need to find where I did that ... That was date/index3.jsp, but at the point I stopped work on it several days ago all it did was give me a blank screen, and write a file on /tmp/ which shows it really did run. Now I need to modify it to output to the JSP 'out' stream... The existing code in date/index3.jsp is: <%@ page import="DispatcherServlet" %> <% dis.doGet(request, response); // **not** the way we should do it!! %> The relevant code in DispatcherServlet.java is: File f = new File("/tmp/log.txt"); PrintWriter pw = null; try { FileOutputStream fos = new FileOutputStream(f); pw = new PrintWriter(fos, true); } catch (java.io.IOException ex) { System.exit(-1); } pw.println("Testing file output from servlet!!"); pw.close(); So let me see if I can re-activate&modify the code that was originally in Dispatcher.java to write to the JSP 'out' stream, first looking at the code as it was, no I was confused, this Dispatcher only had code to read a resource bunble of attributes "messages", not useful to me, looking for that *other* JSP file that did what I remembered, something like response.getStream() or somesuch ... found it, in hello1/Greeting.java, here's the code it had: response.setContentType("text/html"); response.setBufferSize(8192); PrintWriter out = response.getWriter(); out.println("" + "Hello"); out.println("" + "" + "

My stupid name is Duke. What's yours?

" + "
" + (BTW, that word "stupid" was the tiny change I made, causing deployment to produce a bad application that can't allocate servlet, which is why we're now here working through a JSP instead of directly to a HttpServlet.) So let me copy that code (omitting the inclusion of duke.waving.gif, and stopping before the HTML form, just the bare minimum to see if this trick works at all) into my date/DispatcherServlet.java and recompile and see what happens. Edit done, tried recompiling: DispatcherServlet.java:6: cannot resolve symbol symbol : class HttpServlet location: package http import javax.servlet.http.HttpServlet; so I gotta fix those includes ... no, nothing wrong. My utility to look inside the class file and list all methods shows I'm using the correct fully-qualified name of the class: Name of class: javax.servlet.http.HttpServlet 0: public native int java.lang.Object.hashCode() ... 10: public void javax.servlet.GenericServlet.init() throws javax.servlet.ServletException ... so I guess javac doesn't have the needed classpath that my utility has, investigating ... OK, the following command: javac -classpath /usr/java/j2sdkee1.3/lib/j2ee.jar DispatcherServlet.java gives only one error: DispatcherServlet.java:32: unreported exception java.io.IOException; must be caught or declared to be thrown PrintWriter out = response.getWriter(); and that I know how to fix quickly ... I want to catch that exception, and add my own error text and then throw a different kind of exception. I'm guessing the name of the Servlet exception I need to throw is javax.servlet.ServletException, so I go to my utility to find all methods in a class, and indeed I guessed correctly: Name of class: javax.servlet.ServletException ,,, 10: public void java.lang.Throwable.printStackTrace(java.io.PrintWriter) ... 15: public java.lang.Throwable javax.servlet.ServletException.getRootCause() Unfortunately my utility doesn't show the constructors. Fixing it now, but I need to know the method for getting a list of constructors, so I use my utility as-is to get that info: Name of class: java.lang.Class ... 29: public java.lang.reflect.Constructor[] java.lang.Class.getConstructors() throws java.lang.SecurityException so now I know the correct method name, and I can proceed to upgrade my methods-of-class API utility to also show constructors ... done, so here's the new code I added to my utility: Constructor[] cs = c.getConstructors(); for (int i=0; i" + "Hello"); out.println("" + //Omit: "" + "

My stupid name is Duke. What's yours?

"); compiled, and at 11:44 I'm ready to copy the compiled class file to the system area ... that mess with deploytool earlier took so long I forgot where I had the super-user window for updating files on system area, found it, now 12:02, copying compiled class there now ... but the copy of the file on /tmp/ was gone because when I was confused earlier I must have moved it onto J.Random other directory, so I had to find my regular ~/J/New window where I compiled it and make a new copy on /tmp/, done, now 12:07 and I'm ready to reload WebPage and see... crap, still blank screen, and newly-written file on /tmp/ still has the old text from before I made the changes, so it ran the old version again, apparently the server has the file cached and never notices it's been updated on the disk so it never reloads the cashe. I believe if I stop the server and re-start it, this will be fixed. At 12:10 shutting down J2EE server ... done at 12:14, starting server again ... done at 12:19. Earlier today I discovered a way to copy text from an X term window to anywhere else, including emacs. Unlike a DOS window on MS-Windows in campus lab, there's no "mark" option in the menu. But still I can sweep text, and then press [Enter] to copy it, except a newline is transmitted to whatever program is running on that window, so it's not as nice as MS-Windows, and also the window doesn't auto-scroll so I can get one screenfull of text per copy&paste cycle. Using that trick, here's what the j2ee -verbose says, which is a pain because every time it enters a newline it jumps the scroll all the way to the end to show me my input-echo and program's response, so I have to manually scroll back to find where I left off with my copy&paste, but here it is: [root@adsl-63-192-44-196 rem]# j2ee -verbose J2EE server listen port: 1050 Naming service started:1050 Binding DataSource, name = jdbc/InventoryDB, url = jdbc:cloudscape:rmi:CloudscapeDB;create=true Binding DataSource, name = jdbc/DB2, url = jdbc:cloudscape:rmi:CloudscapeDB;create=true Binding DataSource, name = jdbc/EstoreDB, url = jdbc:cloudscape:rmi:CloudscapeDB;create=true Binding DataSource, name = jdbc/DB1, url = jdbc:cloudscape:rmi:CloudscapeDB;create=true Binding DataSource, name = jdbc/Cloudscape, url = jdbc:cloudscape:rmi:CloudscapeDB;create=true Binding DataSource, name = jdbc/XACloudscape, url = jdbc/XACloudscape__xa Binding DataSource, name = jdbc/XACloudscape__xa, dataSource = COM.cloudscape.core.RemoteXaDataSource@4ce7a Starting JMS service... Initialization complete - waiting for client requests Binding: < JMS Destination : jms/Topic , javax.jms.Topic > Binding: < JMS Destination : jms/Queue , javax.jms.Queue > Binding: < JMS Destination : myQueue , javax.jms.Queue > Binding: < JMS Cnx Factory : jms/QueueConnectionFactory , Queue , No properties > Binding: < JMS Cnx Factory : QueueConnectionFactory , Queue , No properties > [[End of that copy&paste, next below]] Binding: < JMS Cnx Factory : TopicConnectionFactory , Topic , No properties > Binding: < JMS Cnx Factory : jms/TopicConnectionFactory , Topic , No properties > Starting web service at port: 8000 Starting secure web service at port: 7000 J2EE SDK/1.3 Starting web service at port: 9191 J2EE SDK/1.3 Loading jar:/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/hello1App1116285872762Server.jar /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/hello1App1116285872762Server.jar Loading jar:/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/conv2App1114556343819Server.jar /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/conv2App1114556343819Server.jar Loading jar:/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/converterApp1113441343351Server.jar /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/converterApp1113441343351Server.jar Loading jar:/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/DateApp1115343413769Server.jar /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/DateApp1115343413769Server.jar [[End of that copy&paste, next below]] Loading jar:/usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/Lab3aApp1115283117550Server.jar /usr/java/j2sdkee1.3/repository/adsl-63-192-44-196.roadguy.com/applications/Lab3aApp1115283117550Server.jar Created Context:/hello1 Binding name:`java:comp/env/ejb/TheConv2` Created Context:/conv2 Binding name:`java:comp/env/ejb/TheConverter` Created Context:/converter Created Context:/date Created Context:/Lab3a J2EE server startup complete. OK, at 12:30, to see whether it will use the updated program of today ... Hey, it works! On the browser screen it says: My stupid name is Duke. What's yours? and let me also look at the /tmp/ file ... yes, that's current too: File output from servlet!! Testing response writer now. So I've learned that to run a HttpServlet I need to call doGet explicitly from a JSP, which I can update at any time and simiply reload WebPage and wait for server to re-compile it, and to make changes in the HttpServlet I need to (1) compile it myself, (2) copy new version of .class file to the public_html directory, sub-directory where the JSP file is, (3) stop the J2EE server and re-start it, and finally (2) reload WebPage. So my plan now is to set up a stdio test rig for initial development, then use a swing test rig for major development, and patch it into the JSP doGet call only once in a while when I want to verify it is compatible with the real live J2EE application environment. Now May.16 12:39, nap time. Back to work at 14:03. During my nap I figured out what to do next: I'll set up a simple stdio test rig whereby I feed in an expression representing name-value pairs, as if they were the contents of an HTML form that the user filled out in the browser. That will be converted into the Request object and passed to the HttpServlet. It will read that info, decide what to do, and put into the Response object a data structure representing the HTML output it wishes to generate. That will be printed to stdout using s-expression notation so I can see what it was. Oops, I totally trashed my edit, must have pressed control-W or somesuch by accident, so I had to copy that paragraph I had just typed without any save to disk, then revert to version that was on the disk, then paste that new text at the end, then look over my file to see if it looks good now. Once I got started looking at the file I noticed some typos and bad formatting, so I scanned the entire file making all corrections that I felt like making. It's now 14:24. So anyway, as I was saying before that interruption: I need a way to print out the Response structured-HTML object, so I'll enhance the toSexpr method I wrote a few days ago to handle this too. I also need to write some kind of parser for some kind of syntax for name/value pairs for the simulated HTML-form contents from stdin, and I have decided to use s-expressions for that too. So I need to write an s-expression parser, nothing complicated, just something able to accept literal string constants, balanced parentheses, and ignoring whitespace between tokens. The first thing to write is a tokenizer, something that takes raw text input and finds where the quoted strings begin and end, converting each such literal string into a single token, and generates a token for each open-paren and close-paren. Starting to write class MyToken at 14:30 ... finished writing constructors, and test suite for validation of parameters (literal string needs a string details parameter, parens must have null pointer as details parameter), and using test suite to discover and fix two bugs (forgot break; statement in last useful clause of switch statement, but default clause threw an exception explaining the problem, and failed to change some text in an exception for bad parameter when I copied it from one method to another so it was giving misleading error message) at 15:39, wrote that up, now at 15:45 it's time to write accessors and predicates (no mutators will be implemented) ... finished at 16:16 including nice printout of all the accessors/predicates: ** Starting test rig for MyToken... * [Token: accessors: getTokenType()=1=LiteralString getDetails()="Hello World!" / predicates: isStringLiteralToken()=true isOpenParenToken()=false isCloseParenToken()=false] * [Token: accessors: getTokenType()=1=LiteralString getDetails()="" / predicates: isStringLiteralToken()=true isOpenParenToken()=false isCloseParenToken()=false] * [Token: accessors: getTokenType()=2=OpenParen getDetails()= / predicates: isStringLiteralToken()=false isOpenParenToken()=true isCloseParenToken()=false] * [Token: accessors: getTokenType()=3=CloseParen getDetails()= / predicates: isStringLiteralToken()=false isOpenParenToken()=false isCloseParenToken()=true] ** Test of constructors&accessors done. Nothing more yet. Next to write a method to convert a token into an atomic external (text) representation of it that can be incorporated into the toSexpr method, starting work at 16:22 ... done with atomic s-expression formatter for MyToken objects, and incorporated into test rig at 16:54, see the output: ** Starting test rig for MyToken... S-expr: Acc/Pred: [Token: accessors: getTokenType()=1=LiteralString getDetails()="Hello World!" / predicates: isStringLiteralToken()=true isOpenParenToken()=false isCloseParenToken()=false] S-expr: Acc/Pred: [Token: accessors: getTokenType()=1=LiteralString getDetails()="" / predicates: isStringLiteralToken()=true isOpenParenToken()=false isCloseParenToken()=false] S-expr: Acc/Pred: [Token: accessors: getTokenType()=2=OpenParen getDetails()= / predicates: isStringLiteralToken()=false isOpenParenToken()=true isCloseParenToken()=false] S-expr: Acc/Pred: [Token: accessors: getTokenType()=3=CloseParen getDetails()= / predicates: isStringLiteralToken()=false isOpenParenToken()=false isCloseParenToken()=true] ** Test of constructors&accessors done. Nothing more yet. Next to modify the Sexpr1.toSexpr(Object) method to call this when needing to print such an object as part of a larger object, starting at 16:56 ... done at 17:12, and here's a printout of the Vector composed of all four valid test cases of token constructor: { } Now I have the tools that when I'm working on the tokenizer, I can print out both individual tokens and Vectors of tokens to see what my program is doing. But I'll take a rest now... Now at 18:40 I'm starting to write the tokenizer ... needed to enhance my conversion of strings to s-expressions to change any " to \" inside strings to make debugging easier, got that done by 21:02 when I started a break to watch the TV progr '24' on FOX. Now 22:11, resuming work on tokenizer ... getOneToken() finished and working at 23:30. One more thing to make, a loop that tokenizes a whole string and returns a list of all the tokens it got ... done at 23:46, here's a transcript of the test of it: ** Starting test rig for MyTokenizerState... * Sample text to parse is "(\"foo\" \"bar\") (\"eripgpicrthcgpimwioop\" \"a\")" Got a token: Got a token: Got a token: Got a token: Got a token: Got a token: Got a token: Got a token: Here I've done it again en masse: { } ** End of MyTokenizerState test rig. So next I start work on the actual s-expression parser at 23:47 ... for debugging I needed an s-expression printer, finished that at May.17 at 00:54, with sample output like this: (("FirstName" "Robert") ("LastName" "Maas") ("City" "Sunnyvale") ("Sex" "Male")) That syntax should be readable by the parser. I think you can see where this is leading even if you missed the earlier notes, namely a way of inputting key-value pairs from a single expression, so that they get passed around in a simple structure similar to a hashmap in semantics, as if they came from HTML form contents (still to do later, the parser itself), and a way to view such structures back in the same s-expression notation (the printer I finished just now). Now at 01:02 it's really time for bed, but I'll upload this first...