About the author
Rick Hightower is CTO of Mammatus and is an expert on Java and Cloud Computing
Tuesday, December 30, 2003
warneronstine.com | home
I get a lot of ideas and inspiration from talking to Warner.
Warner lives in Tucson and is the guy who originally turned me onto PicoContainer and Maven.
Sunday, December 28, 2003
DynaActionForms
one strong point i have against DAF -in XDoclet - try doing validation any easier than that!!!! (can't do it with DAF, that is for sure).
I have used XDoclet's Struts Validator framework support. (BTW That part was written by Erik Hatcher a former co-worker who is still a good friend of mine.) I think XDoclet's Struts Validator framework puts the final nail in the coffin of DAF IMHO.
Like I said before... I can work with them but I don't like them. (not on a tree; not with a bee; not on a bus; not with gus)
Saturday, December 27, 2003
Not a fan of DynaActionForms
DynaActionForms are universally loved and hated. In teaching, consulting Struts and developing with Struts, I have found that DynaActionForms are either embraced or rejected. The idea behind DynaActionForms is that instead of creating an ActionForm per form, you instead configure an ActionForm per form.
Advantages:
Some folks feel creating an ActionForm class for each HTML form in your Struts application is time-consuming, causes maintenance problems, and is frustrating. With DynaActionForm classes you don’t have to create an ActionForm subclass for each form and a bean property for each field. Instead you configure an DynaActionForm its properties, type, and defaults in the Struts configuration file.
Deltas :
You still have to create the DynaActionForm in the struts configuration file. When you use the DynaActionForm, you have to cast all the properties to their known type. Using a DynaActionForm is a lot like using a HashMap. In your Action if you are accessing a DynaActionForm, if you screw up a property name (misspell it) the compiler will not pick it up, instead you will get a runtime exception. If you cast an Integer to a Float by mistake the compiler will not pick it up, you will get a runtime exception. DynaActionForms are not type safe. If you use an IDE, code completion does not work with DynaActionForms. If you override the reset method, you defeat the purpose of having a DynaActionForm. Another point is that DynaActionForms are not very dynamic, as you still have to change the configuration file, and then restart the web application to get Struts to recognize an additional field.
TIP: As you can probably tell, I think using DyanActionForms is less than ideal. I feel DynaActionForms are not really dynamic at all since you have to restart the web application when you change them. I find them no more dynamic than using Java classes. I prefer to create my ActionForms by subclassing ActionForm and using bean properties. I find that modern IDEs make short work of adding JavaBean properties. I see no real advantage to using DynaActionForms over ActionForms. If I want to make an ActionForm dynamic, I add a mapped backed property. I have worked on projects that forced DynaActionForms. I much prefer regular ActionForms.
I can use DynaActionForms. But, I could also code with one hand tied behind my back. In both cases, I don't see why.
AppFuse
What is AppFuse?
An application for starting your web applications. Checkout from CVS and execute "ant -Dapp.name=yourApp -Ddb.name=database" to instantly be up and running with a Tomcat/MySQL app. Uses Ant, XDoclet, Hibernate, JUnit, Cactus, StrutsTestCase, Canoo's WebTest, Struts Menu, Display Tag Library, JSTL and Struts (including Validator and Tiles). Features include CMA, Remember Me, Self Registration, Password Hint. The fuse to start your apps.
Struts IOC
Pretty cool Struts site. They have a plugin that integrates Struts with Spring.
The goals of the Struts Applications Project are:
to provide example Struts applications,
to host Struts extensions and utilities, and
to put the code out where the Community can use it, fix it, and maintain it
The Struts Applications Project currently consists of the following sub- projects:
AppFuse - A baseline Struts application to be used for future web applications
Polls - A survey-management Struts application
Struts Action Invocation Framework (SAIF) - Adds features like Action interceptors and Inversion of Control (IoC) to Struts.
Struts BSF - A Struts Action implementation that uses BSF-compatible scripting languages.
Struts Cocoon - Integrates Struts and Cocoon, using Cocoon for the presentation layer
Struts Resume - An application written using AppFuse as a foundation.
Struts Spring - Integrates Struts and the Spring Inversion of Control (IoC) framework.
StrutsDoc - A JavaDoc-type documentation tool for Struts and Struts-related configuration files
AppFuse
An application for starting your Struts-based applications. Checkout from CVS and execute "ant -Dapp.name=yourApp -Ddb.name=database" to instantly be up and running with a Tomcat/MySQL app. Uses Ant, XDoclet, Hibernate, JUnit, Cactus, StrutsTestCase, Canoo's WebTest, Struts Menu, Display Tag Library, JSTL and Struts (including Validator and Tiles). Features include CMA, Remember Me, Self Registration, Password Hint. The fuse to start your apps.
Polls
A simple survey application. Deploy the .war file on your servlet container to see it running. Read the instructions provided to see all the options available. Uses Hibernate, Struts, and JSTL.
Struts Action Invoocation Framework (SAIF)
A set of Struts extensions to improve how Struts handles Actions adding features like Action interceptors and Inversion of Control (IoC).
Struts BSF
This project allows Struts Actions to be written in the scripting language of one's choice rather than as Java classes. It uses the Beans Scripting Framework to allow scripts to be written in any language BSF supports like Perl, Python, Ruby, JavaScript, and BeanShell.
Struts Cocoon
This is a Struts 1.1 plugin that integrates Cocoon into the Struts framework. Struts forwards are passed to Cocoon to be rendered in Cocoon XML pipelines. Struts is a familiar and proven application framework and Cocoon is a very powerful and flexibile XML presentation technology. The project includes both the plugin and a slightly modified Struts example web application to show how easily Cocoon can be added to an existing Struts application.
Struts Resume
An application written using AppFuse as a foundation. Future plans include the ability to create an online resume and render it's contents with XSL/XML or Velocity.
Struts Spring
This project integrates the Spring Framework's Inversion of Control (IoC) into Struts 1.1+. It allows a Struts application to take advantage of IoC with little or no references to Spring. Now, instead of relying on singletons and static factories, Struts actions can have their dependencies automatically resolved.
StrutsDoc
A JavaDoc-type documentation tool for Struts and Struts-related configuration files. Extensive use of Xalan to transform Struts-related configuration files into text-based documentation.
funny email I got from a good (anoymous friend)
"""
i saw you mentioned Tapestry on your blog - have you tried it? careful if you do, you might be embarrassed to be doing so much with Struts when you give it a try :) we are going full-on with Tapestry at BLANK and loving it!
JSF sucks. money schmoney - i'd rather work at McDonald's than use JSF.
p.s. your blog still looks lousy in Safari - you should try it out on a Mac in Safari sometime and see what i mean.
"""
BTW What is this thing you call Mac? I just bought a new laptop. I considered a Mac. But I bought a really nice 17inch HP laptop for half the price, and it is fast as a bat out of jail. And, the great thing is that all the software I use already works on my HP. I wanted to go with the Mac, but could not. There is this software package I must use that does not run on a Mac yet. (Emulation mode stinks)
Wednesday, December 24, 2003
Hope Springs Eternal
Here is the Spring framework. My pick of the week for interesting things you should look into.
Lions, Tigers, and Bears got nothing on HiveMind, PicoContainer, XWork, Avalon and Spring
Sent : Wednesday, December 24, 2003 3:09 AM
To : "'Richard Hightower'"
Subject : RE: Interesting stuff we talked about.
| | Inbox
Tom Dyer write:
Rick,
Noticed you've looked at Pico Container. Check out the Spring Framework,
cool stuff. Here's a TSS article.
http://www.theserverside.com/resources/article.jsp?l=SpringFramework
Tom,
Tom is right. Spring is cool. It is not longer of matter of whether I will use an IOC container on my next project. It is a matter of which one.
Tuesday, December 23, 2003
What I have been up to
I am really getting into the PicoContainer, Hibernate, Maven, Tapestry and XWork/WebWork. I think JSF will be the next thing that makes money. I wish there were more hours in the day.
Testing JSPs with jWebUnit
jWebUnit makes testing JSP easy by providing a high-level API for navigating web applications. Like StrutsTestCase, jWebUnit provides methods to verify and assert valid conditions. JWebUnit assertion methods relate to navigation and the HTML DOM for example, form entry and submission, validation of table contents, and many common scenarios.
TIP: The book Java Tools for Extreme Programming by Richard Hightower et al covered using JUnit and HttpUnit together to tests Servlets, JSP, Custom Tags and Filters. The chapter on HttpUnit is good background information for understanding jWebUnit. Using jWebUnit is much easier than using JUnit and HttpUnit together.
You can find jWebUnit at http://jwebunit.sourceforge.net/. You can download jWebUnit from http://sourceforge.net/project/showfiles.php?group_id=61302. Download the file jWebUnit-1.1.1.zip. Extract the file and put the jwebunit.jar on the classpath of your IDE project.
The jWebUnit framework depends on the HttpUnit framework so you will need to download HttpUnit. The HttpUnit web site can be found at http://httpunit.sourceforge.net/.
To download HttpUnit go to http://prdownloads.sourceforge.net/httpunit/httpunit-1.5.4.zip?download. Extract the zip file and put the following jar files on your projects classpath js.jar, junit.jar, nekohtml.jar, Tidy.jar, xercesImpl.jar, xmlParserAPIs.jar (found under jars) and of course httpunit.jar (found under lib).
Testing Struts Actions with StrutsTestCase
Using either mode, StrutsTestCase uses the Struts ActionServlet controller to test your Action objects, mappings, form beans and forward declaration. StrutsTestCase provides special assertion methods to assert for example that an action returned a certain forward.
You typically combine StrutsTestCase with Cactus when you have code that depends on J2EE container resources. For example, you have an Action object that depends on local EJB Entity bean. Suffice to say, it is a good idea whenever possible not to rely too heavily on container resources as your code gets tightly coupled with the J2EE environment and harder to test. The problem, with Cactus based StrutsTestCase tests, is that Cactus is hard to setup (but you only have to do it once), and the tests take longer to run than the Mock Object equivalent test.
On the flip side, container simulation—Mock Object based tests require that your action code is not tightly coupled with the underlying J2EE container. This requires a cleaner design and cleaner delineation between your model and the container. Typically, you can get a fairly clean design by using an Abstract Factory from you actions. Thus your actions never directly deal with J2EE, they talk to the Abstract Factory to get model objects. The Abstract Factory may in turn talk to the J2EE services like JNDI to look up and interact with EJBs, etc. Then for testing you create an Abstract Factory that delivers Mock Objects for testing. This is the approach I use. The advantage of using container simulation is you don’t have to deploy your code to the container to test it. In short, the reason to use container simulation is speed. Tests that take a long time to run don’t get run as often. TDD favors fast running tests.
Test Driven Development (TDD) is all the rage. Unlike most development fads this one has staying power. TDD gets its birth from the Agile Development community (http://www.agilealliance.com) and Extreme Programming (XP). Although originally espoused by XP, the main stream uses TDD, which requires fast running, automated tests. The purpose of TDD is to draw out what functionality is really needed, rather than what the programmer thinks is needed. Developing software in a J2EE environment can be fairly tough with its somewhat complex deployment requirements and dependencies on the J2EE container. Layer on top of that the Struts framework and its complexities, and fast automated testing becomes essential. Why essential you ask? It is essential because of speed! By the time, you can deploy, and smoke test a feature or bug fix, using TDD you could do it 4 times.
StrutsTestCase makes TDD possible with Struts.
Monday, December 22, 2003
Struts Training
Sunday, December 21, 2003
jWebUnit
If you know who I am, then you know I have used HttpUnit a lot in the past. I saw jWebUnit mentioned in "Java Open Source Programming", which covers XDoclet, WebWork and Hibernate (I highely reccommend getting this book).
I looked into jWebUnit. Pretty cool stuff. Please check it out. Just look at the first page. Very cool stuff.
I am going to start using jWebUnit where I used to use JUnit and HttpUnit together. jWebUnit builds on top of HttpUnit and JUnit.
This is taken from their site:
Compare this code sample....
package net.sourceforge.jwebunit.sample;
import junit.framework.TestCase;
import com.meterware.httpunit.WebResponse;
import com.meterware.httpunit.WebConversation;
import com.meterware.httpunit.WebForm;
import com.meterware.httpunit.WebRequest;
public class SearchExample extends TestCase {
public void testSearch() throws Exception {
WebConversation wc = new WebConversation();
WebResponse resp = wc.getResponse( "http://www.google.com");
WebForm form = resp.getForms()[0];
form.setParameter("q", "HttpUnit");
WebRequest req = form.getRequest("btnG");
resp = wc.getResponse(req);
assertNotNull(resp.getLinkWith("HttpUnit"));
resp = resp.getLinkWith("HttpUnit").click();
assertEquals(resp.getTitle(), "HttpUnit");
assertNotNull(resp.getLinkWith("User's Manual"));
}
}
To this...
package net.sourceforge.jwebunit.sample;
import net.sourceforge.jwebunit.WebTestCase;
public class JWebUnitSearchExample extends WebTestCase {
public JWebUnitSearchExample(String name) {
super(name);
}
public void setUp() {
getTestContext().setBaseUrl("http://www.google.com");
}
public void testSearch() {
beginAt("/");
setFormElement("q", "httpunit");
submit("btnG");
clickLinkWithText("HttpUnit");
assertTitleEquals("HttpUnit");
assertLinkPresentWithText("User's Manual");
}
}
PicoContainer -
I read through the docs on this site. I really dig this type 3 Inversion of Control Container.
If you get a few minutes, check the site out. It only takes a few minutes to get what they are trying to do, and it makes so much sense.
Starbucks in Tucson
Erik Hatcher at java.net
What a terrible friend I am.... I just read Erik's stuff on java.net... it has been there for six months. It was fun haning out with Erik at JavaOne.
Cool stuff. Erik Rocks! I agree about the scripting languages. Why make JSR-223 Web centric? (I acutally care about scripting. I wrote a book on Jython and several articles on Jython, NetRexx, Bean Scripting Framework, etc. I hope scripting goes more main stream.)
I am happy to see JSP support other languages. Although with JSTL, I think it is a lot less of an issue than it was before. I guess this is mostlly to win over the PHP crowd.
Nutch sounds cool (see above link for more detail).
Rick's Resume
My resume use to show up second when you searched for "Rick Resume" in google.
Now it has dropped down to third. (I don't know why it was second.)
Anyway, my resume is a bit dated.
Saturday, December 20, 2003
Good article in this month's edition of Dr. Dobbs; porting Jakarta Lucene to J#
Tuesday, December 16, 2003
Master the Tiles Framework with this tutorial....
In some respects, the tile layout is like a display function. First you pass tile layout parameters to use. The parameters can be simple strings, beans, or tiles. The parameters become attributes to the tile and get stored in the tile's tile scope. For its part, the tile scope resembles page scope, and is less general than request scope. The tile scope lets the tile's user pass arguments (called attributes) to the tile.
Definitions let you define default parameters for tiles. Definitions can be defined in JSP or XML. Definitions can extend other definitions similarly to how a class can extend another class. Moreover, definitions can override parts of the definition it is extending.
The Tiles framework includes its own RequestProcessor to handle tile layouts as ActionForwards. Thus you can forward to a tile definition instead of a JSP if you install the Tiles plug-in.
If you are using Struts but not Tiles, then you are not fully benefiting from Struts and likely repeat yourself unnecessarily. The Tiles framework makes creating reusable site layouts and visual components feasible.
In this tutorial you will cover the following:
- The Tiles framework and architecture
- How to build and use a tile layout as a site template
- How to use tile definitions both in XML and JSP
- How to move objects in and out of tile scope
- How to work with attributes lists
- How to nest tiles
- How to build and use tile layouts as small visual components
- How to subclass a definition
- How to create a controller for a tile
- How to use a tile as an ActionForward
Good book... get it quick.... covers XDoclet, Hibernate, XWork, WebWork, Ognl, Jakarta Commons, SiteMesh and IOC, etc.
I've just read a few chapters and skimmed the rest of the book. This book is a classic. Hats off to the authors... Ara Abrahamian, Joe Walnes, Mike Cannon-Brookes, and Pat Lightbody. I can't wait to dig into this book into detail.
So far, all I can say is WOW! Good Stuff. Sucky title.... great book.
The book is called Java Open Source Programming by Wiley Press.
I am more of a Struts, Hibernate, XDoclet, Tiles, and JSTL EL person myself but it is good to learn more about WebWork, OGNL, etc.
Here is an update.... I have been digging in even deeper. I really love this book. I really the ideas behind XWork.
Friday, December 05, 2003
Tuesday, December 02, 2003
Accessing a Database from Struts using Struts Datasources
Datasource, DBCP documentation woes, suggested documentation fix
You need booth commons-pooling and commons-dbcp to get Struts Datasources to work, but this is not mentioned in the documentation and the required jar files do not ship with Blank.war. In fact in Struts 1.1., you also need Struts Legacy jar file as well. Of course, if you are using Tomcat then both commons-pooling and commons-dbcp ship in the shared folder but you do need to download them if you are using another application server. You do need to download them only f you are going to use Struts Datasources.
I think either
http://jakarta.apache.org/struts/userGuide/configuration.html#data-source_config
or
http://jakarta.apache.org/struts/faqs/database.html
should make note of this.
Here is a stab at it.
Struts Datasources require commons-pooling and commons-dbcp. The blank.war does not have commons-pooling or commons-dbcp. If you want to use Struts datasource, you will need to download commons-pooling and commons-dbcp from the following locations:
http://jakarta.apache.org/site/binindex.cgi#commons-dbcp
http://jakarta.apache.org/site/binindex.cgi#commons-pool
Download the above archives and un-archive them. Then copy the jar files commons-pool-1.1.jar, and commons-dbcp-1.1.jar into the WEB-INF/lib directory of your web application. Note that Tomcat 5 ships with commons-dbcp and commons-pool so you do not need to download and install commons-dbcp and commons-pool if you are using Tomcat.
In addition to the above two jar files, you will need to use the struts-legacy.jar jar file that ships with Struts 1.1. Copy the struts-legacy.jar file to the WEB-INF/lib directory of your web application.
This might be a moot point depending on how soon Struts 1.2 comes out, and if commons-pooling and commons-dbcp ship with Struts.
Rick Hightower
Chief Technology Officer
ArcMind
“Know the Next!”
http://www.arc-mind.com
Friday, November 28, 2003
My first Fan
Dear Mr. Hightower,
I am truly impressed by your technical achievements. I have been looking for (advice on) my career ...
My ambition is to be close to what you have done in your career....
I already have a head start with an Engineering degree in Electronics, and a Master's Degree in CS. Also, I have about 10 certifications including J2SE 1.4 and SCWCD (with 93%).
I am eagrly waiting for your response.
NAME_WITHHELD_TO_PROTECT_THE_INNOCENT
Indiana, USA.
I doubt I will get email like tihs very often so I suppose I should enjoy it or something.
I admire Martin Fowler, Kent Beck, Robert Orfalli, James Gosling, Drew Davidson, Erik Hatcher, Dan Harkey, Nick Lesiecki, Grady Booch, Peter Coad and many more. I have had the pleasure of meeting and talking to a lot of folks on my list in person, though I doubt any of them remember me. I worked with Erik, Nick and Drew at eBlox so they have to remember me. Everyone I met was extremely nice.
My first Fan
Dear Mr. Hightower,
I am truly impressed by your technical achievements. I have been looking for (advice on) my career ...
My ambition is to be close to what you have done in your career....
I already have a head start with an Engineering degree in Electronics, and a Master's Degree in CS. Also, I have about 10 certifications including J2SE 1.4 and SCWCD (with 93%).
I am eagrly waiting for your response.
NAME_WITHHELD_TO_PROTECT_THE_INNOCENT
Indiana, USA.
I doubt I will get email like tihs very often so I suppose I should enjoy it or something.
I admire Martin Fowler, Kent Beck, Robert Orfalli, James Gosling, Drew Davidson, Erik Hatcher, Dan Harkey, Nick Lesiecki, Grady Booch, Peter Coad and many more. I have had the pleasure of meeting and talking to a lot of folks on my list in person, though I doubt any of them remember me. I worked with Erik, Nick and Drew at eBlox so they have to remember me. Everyone I met was extremely nice.
My first Fan
Dear Mr. Hightower,
I am truly impressed by your technical achievements. I have been looking for (advice on) my career ...
My ambition is to be close to what you have done in your career....
I already have a head start with an Engineering degree in Electronics, and a Master's Degree in CS. Also, I have about 10 certifications including J2SE 1.4 and SCWCD (with 93%).
I am eagrly waiting for your response.
NAME_WITHHELD_TO_PROTECT_THE_INNOCENT
Indiana, USA.
I doubt I will get email like tihs very often so I suppose I should enjoy it or something.
I admire Martin Fowler, Kent Beck, Robert Orfalli, James Gosling, Drew Davidson, Erik Hatcher, Dan Harkey, Nick Lesiecki, Grady Booch, Peter Coad and many more. I have had the pleasure of meeting and talking to a lot on folks on my list in person, though I doubt any of them remember me. I worked with Erik, Nick and Drew at eBlox. Everyone I met was extremely nice.
Tuesday, November 11, 2003
Mock Object Testing: A new respect for it
Cool project, a lot of fun, Tiles, lots of tiles (Struts chicken richness)
Later I worked on a pagination piece and a embeded Search piece. I used Tiles for both. I dig Tiles and Tile controllers.
Sunday, November 09, 2003
Note to self.... write down the user name and password
So now I uninstall and reinstall.... This time I will write it down.
1/2 hour later. Now that I have uninstalled an reinstalled. I realize that the install never asked me for a username and password. Great.
New Company...... Arc-Mind.... Know the Next!
I'd like to announce to anyone who cares that I am available for work. I am pretty well booked for the next few months, but I am sure I can fit some more work in. :o)
Saturday, November 08, 2003
Fr33D0M
Erik wrote...
Yup, I resigned my full-time day job position.
But rather than taking a new job, I'm going to continue contracting with them on a half-time basis. And just so you readers don't get the wrong impression, don't go write a book thinking you can quit your day job and rest easy on royalties. I'm taking a huge financial hit as well as a fairly sizeable risk. But risks make it all worthwhile.
My last day was last Monday. I gave a one month notice too, and Monday was the last day. I don't have a new job. I did start my own company. I do have a *lot* of contract work. I am working on another book too. And, I am working as a consultant to my last company on a part time basis. How is that for being in sync. with the Hatch!
I worried for a long time. I have had a lot of success at all the companies I have worked for. And... this has been a slow progression going from smaller company to smaller company.... And then finally on my own! It feels good! Really GOOD!
Friday, November 07, 2003
Wired, then Tired: A good coding session ends the week on a positive note.
I love speaking, writing and teaching, but I must admit I enjoy coding the best. Especially when I get in the zone! I wish all days could be like last Thursday.
Tuesday, November 04, 2003
Read-Rite Corporation goes away... a sad day!
Goodbye old friend! I'll miss you. I got my start at Read-Rite. I did not
learn to program there, but I sure honed my software development skills there. I will always
remember: Dave, Balaji S., Vince R., Rick K., and Peter B.
On or about June 17, 2003, Read-Rite Corporation ceased operations and filed for Chapter 7 bankruptcy in the United States Bankruptcy Court for the Northern District of California, Oakland Division, Case No. 03-43576 RN-7.
Please send inquiries concerning Read-Rite Corporation to:
Tevis T. Thompson, Jr.
Trustee for the Bankruptcy Estate of Read-Rite Corporation
c/o Jeremy W. Katz, Esq.
Pinnacle Law Group
425 California Street, Suite 1800
San Francisco, CA 94104
Struts and IBM developerWorks
DeveloperWorks has been covering Struts for a long time and has quite an array of timely material on Struts.
- Struts, an open-source MVC implementation
- Struts and Tiles aid component-based development
- Struttin' your stuff with WebSphere Studio Application Developer, Part 2: Tiles
- Integrating Struts, Tiles, and JavaServer Faces
- Architect Struts applications for Web services
- Go-ForIt Chronicles, Part 19: Struttin' your stuff with WebSphere Studio
I particularly liked the Go-ForIt Chronicle series and the Integrating Struts, Tiles, and JavaServer Faces.
If you are jonesing for some Struts information, IBM developerWorks is the place to get your Struts fix.
Oh yeah... don't forget to get a copy of James and I's new Struts book: Professional Struts.
It is the most up to date Struts book, and it covers the Validator Framework and the Tiles Framework in detail.
Thursday, October 30, 2003
This year is winding up.... it has been a good year
This last month. I've been doing a lot of work with Struts for this client. There system is well designed and thought out and a real pleasure to work on.
I just wrote a pagination tile/tile controller. Earlier I wrote a navigation system, essentially a Struts plugin that does secured menuing. (Only shows menu's user are allowed to visit.)
I've also been helping to resolve build issues and J2EE environment issues (classloader, jars in the wrong location, etc.) In addition, I have been doing a lot of mentoring. Developers come to me with their Struts/J2EE questions and we figure things out together. It helps "to have been there and done" that many times before.
The navigation system worked really well until we integrated it wtih the real security system. There was some integration pain and some late night coding sessions, but in the end it works really well. It was architected well.
I wrote a replacement for LookupDispatch that allows multiple buttons on the same page to have the same label.
I spent a fair bit of time wrestling with CSS to make buttons look like links and work in both Netscape 6.22 and IE 5.0 and higher (the requirement for the project).
We were able to avoid requiring JavaScript and still meet the fairly rigid GUI guidelines.
More to come.....
Next time I will write about the joys of Mock Object testing...
I've moved on over into the Mock Object testing love fest crowd, and I have started to not rely on Cactus so much.
Tuesday, October 21, 2003
IBM Web Service Wizards
Saturday, October 11, 2003
Wireless Modem, StarBucks, WebLogic 7, Mastering BEA WebLogic
I got tired of not being able to connect. A lot of my clients have their networks locked down so its hard for me to send and recieve email. This way, I can stay connected no matter where I am. Some hotels have high speed, and some of the actually work, but why pay $10.00 a night.
I figured out how to use an exploded EAR file with an exploded WAR file in BEA WebLogic 7. I found the information on google. The info was written by the author of Mastering BEA WebLogic. So I figured it was in his book as well. BTW I really dig Mastering BEA WebLogic.
I got use to using WebLogic 8.1 which automatically expands EAR and WARs and lets you hot deploy JSPs and such.
Well I am off to StarBucks to write an article about Custom Tags and drink some liquid motivation.
Thursday, October 09, 2003
Tuesday, October 07, 2003
Yet Another Discovery with LookUpDispatch and the resouce bundles
However, when you invoke an LookUpDispatchAction the first time, it cannot find the bundle/key if it is not the default. The second time and forevermore, it works.... it just fails the first time.
This may be a bug.
Another resoruce bundle discovery
It is the last bundle without a key. We found this out the hard way!
Struts 1.0 overides 1.1 resource bundle
Appraently if you have the application init parameter set for ActionServlet (which specifies the resoruce bundle), it overrides the one that is set in struts-config with message-resoruces.
The moral of this story, don't use the 1.0 init parameters with a 1.1 application.
Thursday, September 11, 2003
fun at Venice Beach
It gave me a chance to evaluate goals and priorities and sort of meditate while listening to the ocean. I love the ocean. I love the sound and the smell.
As I traveled west of Venice Blvd. I ....
Friday, September 05, 2003
How to ask a question?
Most times these questions are pretty vague.
Jame Peterson knows how to ask a question.
He wrote me a little document that walks me through his environment. Pretty cool.
BTW I was still not able to really answer his question. It works on my box not on his.
Response
But at least I was able to try.
Wednesday, September 03, 2003
Tuesday, September 02, 2003
Will program Swing for remodeling.... (one day of my labor day)
I took some Excel spreadsheets that they used to track some billing data. I converted the highly unnormalized data from the Excel spreadsheet to a normalized set of database tables. I had to write a script in Python that would clean up the redundant data and arrange it into normalized tables (this was the longest part). I have to admit; I love this type of programming.
I then wrote a simple GUI to track items to bill. You enter in the serial number of the item, it shows its picture plus a list of maintenance parts. You just pick the part and the qty and hit add. Simple, but fun to write. I wrote it all in Swing.
It took me one day to write the data normalizer and the GUI.
You can add an optional date field (it defaults to today). I used the InputVerifier so you can't leave the date field until you enter in a proper date. I use labels associated with components that have displayMnemonics to make navigation easy.
90% of the GUI is written in HTML (I know I said swing, but swing does HTML). I use an EditorPane with its content type set to text/html. This allows me to easily put up pretty pictures of the machines (the machine changes based on the serial number), the company logo, the vendor logo, etc. I wrote the whole thing in Jython (Python running in the JVM).
I have a text field to enter in the serial number.... as you enter in the serial number, it highlights the closest serial number in a list, once you get close entering in the 10 digit serial number, you can pick it from the list. Then it pulls up that product data in a editable view (with a picture of the machine and a list of parts you can change).
I have to admit programming in Swing was fun, and a nice break from programming in Struts.
I am a big fan of Jython. I guess that is why I wrote a book on it. (Based on the book sales, there aren't as many jython fans as I would like.)
Thursday, August 28, 2003
Looking for something else and I ran into this....
Picked up that one yesterday. I bought it cause Rick Hightower (Java Tools for Extreme Programming) wrote the chapter on struts and ant/xdoclet. I haven't been able to go through the whole thing yet, but I need good reference info and insight into how the new Jasper2 engine handles caching of tag libs and some of the quirks that come up in JSP/Servlet development WRT insuring clean separation of data in the various scopes. I'm also very interested in seeing how struts and the JSTL should behave in the container.
I want a raise from Wiley.
Improve JSTL i18n support with Struts
I have a suggestion along these lines. (This is prelim. I am going to write some tests and do some prototyping but before I do… I’d like to hear if there are any thoughts on this).
Currently when you call Action.setLocale you get this:
...class Action...
protected void setLocale(HttpServletRequest request, Locale locale) {
HttpSession session = request.getSession();
if (locale == null) {
locale = Locale.getDefault();
}
session.setAttribute(Globals.LOCALE_KEY, locale);
}
I am suggesting this (for the release that embraces JSTL…. Struts 1.3 or 1.5).
import javax.servlet.jsp.jstl.core.Config; //get this guy to use its Locale key as well ...class Action...
protected void setLocale(HttpServletRequest request, Locale locale) {
HttpSession session = request.getSession();
if (locale == null) {
locale = Locale.getDefault();//Don’t agree with this, but that is a different story…
}
session.setAttribute(Globals.LOCALE_KEY, locale);
session.setAttribute(Config.FMT_LOCALE, locale); //See this…. See this…. See this…
}
The Config.FMT_LOCALE is similar to the Globals.LOCALE_KEY except that it is for the JSTL tags, e.g.,
This is one possibility and the one that takes the least amount of effort. Another possibility is to change all struts i18n tags to use Config.FMT_LOCALE instead of Globals.LOCALE_KEY, which might be bad because it would break existing projects.
I am going to write a prototype along these lines in the near future. I need to test to see if fmt:message will work with Strut’s resource bundles. (I am not sure it they will or not... I think they will with a little arm twisting. I am still a little ignorant on the details... I got the big picture... just not all the details.). Any suggestions from you i18n gurus would be nice or if someone already started this... clue me in so I don't waste time.
This could be a first step in getting rid of our good friend bean:message and replacing him with fmt:message (or at least deprecating him a bit). :(
Don’t worry. I will add this to the Bugzilla feature request as soon as I test it.
APIs of the World Unite.... Fail Loud and Proud (Struts Action.setLocale)
protected void setLocale(HttpServletRequest request, Locale locale) {
HttpSession session = request.getSession();
if (locale == null) {
locale = Locale.getDefault();
}
session.setAttribute(Globals.LOCALE_KEY, locale);
}
Comments on setLocale from Action..
If the locale is null, wouldn't it be better for the default to come from the request as in request.getLocale(), which is the behavior of the tags when the Locale at Globals.LOCALE_KEY is not in session scope.
Better Yet.... Also if they call setLocale, shouldn't the local object be non-null. My personal opinion on this stuff is that it should explode with an illegal argument exception. (I remember a bug report that talked about Struts quietly handing illegal situations... this has been a long time complaint about Struts)
if (locale == null) {
throw new java.lang.IllegalArgumentException("Locale was null");
}
As a developer when I misuse an API, I like to see it fail quickly. This way I don't have to spend a lot of time debugging where I went wrong. Die early and often in development not during QA or. gulp.. Production!
Monday, August 25, 2003
Struts JSTL EL Validator rule
I tried to contribute it. I subscribed to the struts dev list, and posted the following:
I am new to this list so I apologize if I break any etiquette. I was thinking that I don't like validatewhen or requiredif so I wrote my own that uses JSTL EL. (I like the idea behind requiredif and validatewhen just not the implementation.) I believe this approach has several advantages over requiredif and validatewhen. I call this new rule validateel (I have not thought of a better name for it yet...).
Why write your own expression language? Why not use OGNL or JSTL EL? I think JSTL makes the most sense for the followig reasons:
1) EASY TO LEARN
The first advantage of this approach is it is easy to learn since developers know JSTL EL already. JSTL EL is easy to learn and you have to learn it for JSP 2.0 anyway. In fact, developers should be using JSTL tags in place of logic:* tags already.
2) ACCESS TO PAGE CONTEXT
The nice thing about this rule is that it has access to the complete pageContext (Headers, Request Parameters, Session, the whole thing) name space like any JSTL tag. (more on this trick later).
Since I am using JSTL EL I can make my expression as complex as need be, e.g., I can check to see if one date is before another or if a string starts with a certain substring. It is completely powerful, and yet very easy to learn and use.
3) VERY LITTLE CODE
This rule was very easy to implement. It relies on the Jakarta JSTL EL implementation. I don't see the point in adding a new expression language just for Struts when Struts relies on JSP and Servlets and JSP will be using JSTL. (Less code to add means less code to maintain....)
DETAILS:
...
(the rest you have seen in my blog)
This message was far more democratic and polite than my blog entry.
Thursday, August 21, 2003
What is requiredif and validatewhen.....??? (Struts validator)
They (requiredif and validatewhen) both account for...making fields required based on the value of other fields, or checking a relationship between fields.
So here goes....
Let's assume you want to make the state fields (as in a US state like a province in other countries) conditionally required only if the US checkbox field is set or the country drop down field is equal to the country code “us”. You would use the requiredif rule. The entry in your validation.xml file would look like this:
<form name="inputForm">
<field
property="state" depends="requiredif">
<arg0 key="inputForm.state "/>
<var>
<var-name>field[0]</var-name>
<var-value>us</var-value>
</var>
<var>
<var-name>fieldTest[0]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[0]</var-name>
<var-value>true</var-value>
</var>
<var>
<var-name>field[1]</var-name>
<var-value>country</var-value>
</var>
<var>
<var-name>fieldTest[1]</var-name>
<var-value>EQUAL</var-value>
</var>
<var>
<var-name>fieldValue[1]</var-name>
<var-value>us</var-value>
</var>
<var>
<var-name>fieldJoin</var-name>
<var-value>OR</var-value>
</var>
</field>
The field[n], fieldTest[n] and fieldValue[n] variables setup the expression. Thus the above states that in order for state to be required the us field has to equal “true” or country has to equal “us”. The fieldJoin variables joins the two expression. The fieldJoin value can be OR or AND, if AND then both of the expression have to be true. In addition to using EQUAL as a fieldTest, you can also use NULL and NOTNULL to see if the related properties are NULL or not.
The above is nice because it negates the need to override the ValidateForm’s validate method. However, it would not work for our password example earlier. For that more would be needed.
Requiredif might be deprecated in future releases
Future version of Struts passed version 1.1 may deprecate requiredif. The requiredif is considered very complex, especially when dealing with indexed fields (arrays of beans). The recommended way to perform this type of validation will be with the validwhen rule.
Beyond 1.1 conditional validation
As we showed earlier it is often the case that fields are validated based on the value of other fields. The example we did earlier in the chapter regarding password fields that are only valid if they are equal to each other. Thus we need to do more complex expressions than the requiredif rule provides. The validwhen validation rule is designed to handle these types of validation but it is not available until the release beyond 1.1. If you want in now, you will have to download the nightly source.
The validwhen rule takes a single test variable. The value of test must be a boolean expression. You can also refer to the current field under test with the keyword *this*. An example of using this with our password example is as follows:
<field property="password" depends="validwhen">
<arg0 key="inputForm.password"/>
<var>
<var-name>test</var-name>
<var-value>
((passwordCheck != null) and (*this* == passwordCheck))
</var-value>
</var>
</field>
The above would perform the same type of validation as the example we had earlier which required us to use override the validate method of the ValidateForm.
Here's a an example that redoes the requiredif example with validwhen as follows:
<field property="state" depends="validwhen">
<arg0 key="inputForm.state"/>
<var>
<var-name>test</var-name>
<var-value>
((us == "true") or (country == "us"))
</var-value>
</var>
</field>
You can also use validwhen with indexedProperties. Let’s say that the user registration form had two address, home address and shipping address. You would only want to validate the zip if address line one was set, you would use the following entry in the validation.xml file.
<field property="zip" indexedListProperty="addresses" depends="validwhen">
<arg0 key="inputForm.zip"/>
<var>
<var-name>test</var-name>
<var-value>((addresses [].addressLine1 == null) or (*this* != null))</var-value>
</var>
</field>
The address[] corresponds to the array of JavaBeans (e.g., ch15.Address). You are stating that the addresses[].zip is only required if the addresses[].addressLine1 is set.
Validator Rule that uses JSTL EL to validate multiple fields (and I hate coneys)
I was thinking how much I hate requiredif validator. I was also thinking that I don't like validatewhen much better.
Why write your own expression language? Why not use Ognl or JSTL?
I wrote my own version of validatewhen, and it uses JSTL lib from the Jakarta tag project. It took me about 20 minutes to write this. Short, sweet, and I'll never use validatewhen or requiredif again!
In my opinion, this new validate rule is much better than requiredif or validatewhen (at least the versions that I messed with). I can't believe someone did not think of tihs sooner.
It is also really easy to learn since you should know JSTL already.... Nothing special past that! (JSTL is easy and you have to learn it for JSP 2.0. You should be using JSTL tags in place of logic:* tags already.).
I call this new rule validateel (i have not thought of a better name for it yet... but I will, let me know if you think of one).
The nice thing about this rule is that it has access to the complete pageContext name space like any JSTL tag.
(more on this trick later).
Here is an example of using this rule to check to see if a passwordCheck field is equal to a password field as follows:
<field property="passwordCheck"
depends="validateel">
<arg0 key="inputForm.passwordCheck"/>
<var>
<var-name>test</var-name>
<var-value>
${value==form.password}
</var-value>
</var>
I created a FakePageContext class that takes a HttpServletRequest, and mocks up page context. I then add form to the fake page context as well as value inside of my new rule as follows:
PageContext pageContext = new FakePageContext(request);
String test = field.getVarValue("test"); //Get the test var (this is the JSTL expression)
pageContext.setAttribute("form",bean); //Map in the form
pageContext.setAttribute("field",field); //Map the field object (Just in case)
String value = ValidatorUtil.getValueAsString(bean, field.getProperty()); //Get the value of the property
pageContext.setAttribute("value",value); //Map the value into the page context.
The workhorse that actually does the JSTL expresion evaluation is from the JSTL lib. I just invoke it as follows:
result = (Boolean) ExpressionEvaluatorManager.evaluate("validateEL", test, Boolean.class, pageContext);
This was so easy... and IMHO it is better than requiredif and validatewhen. First... it uses JSTL which is an expression language people either know or should know (as it is required knowledge in JSP 2.0).
Here is the complete ValidateEL method and imports that implements this new validator rule.
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.ValidatorAction;
import org.apache.commons.validator.ValidatorUtil;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.validator.Resources;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
/**
* @author rhightower
*
*/
public class CustomValidatorRules {
public static boolean validateEL(
Object bean,
ValidatorAction va,
Field field,
ActionErrors errors,
HttpServletRequest request) {
PageContext pageContext = new FakePageContext(request);
String test = field.getVarValue("test");
pageContext.setAttribute("form",bean);
pageContext.setAttribute("field",field);
String value = ValidatorUtil.getValueAsString(bean, field.getProperty());
pageContext.setAttribute("value",value);
Boolean result = Boolean.FALSE;
try{
result = (Boolean) ExpressionEvaluatorManager
.evaluate("validateEL",
test,
Boolean.class,
pageContext);
}catch (JspException je){
// TODO fix
je.printStackTrace();
}
boolean r = result.booleanValue();
if (r == false){
errors.add(
field.getKey(),
Resources.getActionError(request, va, field));
}
return r;
}
....
Here is the listing for the FakePageContext (it fakes the needed parts of the context and leaves the rest noops):
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
/**
* @author rhightower
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class FakePageContext extends PageContext {
HttpServletRequest request;
Hashtable map = new Hashtable();
public FakePageContext(HttpServletRequest request){
this.request = request;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getAttribute(java.lang.String)
*/
public Object getAttribute(String key) {
return map.get(key);
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String key, Object value) {
map.put(key, value);
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#removeAttribute(java.lang.String)
*/
public void removeAttribute(String key) {
map.remove(key);
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getOut()
*/
public JspWriter getOut() {
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getSession()
*/
public HttpSession getSession() {
return request.getSession(true);
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getPage()
*/
public Object getPage() {
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getRequest()
*/
public ServletRequest getRequest() {
return this.request;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getResponse()
*/
public ServletResponse getResponse() {
// no op
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getException()
*/
public Exception getException() {
// no op
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getServletConfig()
*/
public ServletConfig getServletConfig() {
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getServletContext()
*/
public ServletContext getServletContext() {
return null;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#forward(java.lang.String)
*/
public void forward(String arg0) throws ServletException, IOException {
//no op
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#include(java.lang.String)
*/
public void include(String arg0) throws ServletException, IOException {
//no op
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#initialize(javax.servlet.Servlet, javax.servlet.ServletRequest, javax.servlet.ServletResponse, java.lang.String, boolean, int, boolean)
*/
public void initialize(
Servlet arg0,
ServletRequest arg1,
ServletResponse arg2,
String arg3,
boolean arg4,
int arg5,
boolean arg6)
throws IOException, IllegalStateException, IllegalArgumentException {
//no op
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#setAttribute(java.lang.String, java.lang.Object, int)
*/
public void setAttribute(String key, Object value, int scope) {
if (scope ==PageContext.PAGE_SCOPE){
map.put(key, value);
}else if (scope == PageContext.REQUEST_SCOPE){
request.setAttribute(key,value);
}else if (scope==PageContext.SESSION_SCOPE){
request.getSession().setAttribute(key,value);
}else if (scope==PageContext.APPLICATION_SCOPE){
//TODO fix
}
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getAttribute(java.lang.String, int)
*/
public Object getAttribute(String key, int scope) {
if (scope ==PageContext.PAGE_SCOPE){
return map.get(key);
}else if (scope == PageContext.REQUEST_SCOPE){
return request.getAttribute(key);
}else if (scope==PageContext.SESSION_SCOPE){
return request.getSession().getAttribute(key);
}else if (scope==PageContext.APPLICATION_SCOPE){
return null; //TODO fix
}else {
return null;
}
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#removeAttribute(java.lang.String, int)
*/
public void removeAttribute(String key, int scope) {
if (scope ==PageContext.PAGE_SCOPE){
map.remove(key);
}else if (scope == PageContext.REQUEST_SCOPE){
request.removeAttribute(key);
}else if (scope==PageContext.SESSION_SCOPE){
request.getSession().removeAttribute(key);
}else if (scope==PageContext.APPLICATION_SCOPE){
//TODO fix
}else {
// no op
}
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getAttributeNamesInScope(int)
*/
public Enumeration getAttributeNamesInScope(int scope) {
if (scope ==PageContext.PAGE_SCOPE){
return map.keys();
}else if (scope == PageContext.REQUEST_SCOPE){
return request.getAttributeNames();
}else if (scope==PageContext.SESSION_SCOPE){
return request.getSession().getAttributeNames();
}else if (scope==PageContext.APPLICATION_SCOPE){
return null; //TODO fix
}else {
return null;
}
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#getAttributesScope(java.lang.String)
*/
public int getAttributesScope(String arg0) {
// No op
return 0;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#findAttribute(java.lang.String)
*/
public Object findAttribute(String key) {
Object value = map.get(key);
if (value == null){
value = request.getAttribute(key);
}
if (value == null){
value = request.getSession().getAttribute(key);
}
if (value == null){
//TODO look it up in app scope
}
return value;
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#handlePageException(java.lang.Exception)
*/
public void handlePageException(Exception arg0)
throws ServletException, IOException {
// No op
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#handlePageException(java.lang.Throwable)
*/
public void handlePageException(Throwable arg0)
throws ServletException, IOException {
// No op
}
/* (non-Javadoc)
* @see javax.servlet.jsp.PageContext#release()
*/
public void release() {
// No op
}
}
For completeness...
I had to add this entry in validation-rules.xml
<validator name="validateel"
classname="ch15.CustomValidatorRules"
method="validateEL"
methodParams="java.lang.Object,
org.apache.commons.validator.ValidatorAction,
org.apache.commons.validator.Field,
org.apache.struts.action.ActionErrors,
javax.servlet.http.HttpServletRequest"
msg="errors.validateEL">
</validator>
It took me longer to write this blog entry then it did to write the above code. IMO if you are using requiredif or validatewhen, then you are wasting your time. Also, if you use the validator framework and you ever need to do a simple comparison of two fields... this is the way to go. With JSTL you have access to headers, attributes in session, request attributes, request parameters, and so much more.... Use this... it works and it is cool.
Here is how I would do the above in my own validate method of an ActionForm (for reference).
public class InputFormAll extends ValidatorForm {
...
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = super.validate(mapping, request);
if (!(password.equals(passwordCheck))){
errors.add(
"password",
new ActionError("errors.password.nomatch"));
}
return errors;
}
Using validateel is so much more terse!
${value==form.password}
and I am done!
Tuesday, August 19, 2003
Proud Mary's.... I love it.... WIFI and Burgers!
I am in Cincinnati and my hotel does not have high speed access. I was working in my hotel room with a dial-up modem.... Yuck!
I saw this place last night, and thought I would give it try.
Proud Mary's Burgers..... (near the down town library).
Turns out Proud Mary's has Hi Speed Access (WIFI baby), and yes I did bring my laptop (eventhough I did not know about the WIFI).
I have not tried the food yet (still waiting), but WIFI access is great!
Should frameworks fail when you do something stupid? I think so... fail fast and early (preconditions rule!)
Let's say I have a the following code that adds a checkbox, label and text field to a container.
The code is setup to allow the text field to stretch horizontally as follows:
JFrame frame = new JFrame(); //Create the frame.
JPanel content = new JPanel(); //Create the panel to hold the label and text field
frame.getContentPane().add(content); //Add the panel to the frame
content.setLayout(new GridBagLayout()); //Set the panel layout to GridBagLayout
JLabel label = new JLabel("Enter Name:"); //Create a label
JTextField field = new JTextField(10); //Create a text field
JCheckBox checkbox = new JCheckBox(); //Create checkbox
GridBagConstraints constraints = new GridBagConstraints(); //Create a constraint
//Add the label with the defaults
content.add(checkbox); //Add the label using defaults, OPPS!
constraints.gridx=1;
content.add(label); //Add the label using defaults, OPPS!
//Add the field to show to the right of the label,
//and take up the rest of the leftover space.
constraints.gridx=2;
constraints.fill=GridBagConstraints.HORIZONTAL; //Stretch horizontally
constraints.weightx=1.0; //Take up the rest 1 of 1
content.add(field); //OPPS!
frame.pack();
frame.setVisible(true);
Do you see what is wrong....
I forgot to use the constraint when I call add.
What happens? A nasty exception telling me that I dumb and forgot the constraint? Nope. I wish.
It happily add the fields with the defaults, which kind of behaves like FlowLayout.
I'd prefer if the framework would fail quickly, and let me know I screwed up.
The add method should throw some kind of precondition assertion. "Hey dummy you forgot to use a constraint" Exception. Instead of making me stare at the code. What if I forget? Let me know. This makes the framework easier to use.
The following code is correct....
JFrame frame = new JFrame(); //Create the frame.
JPanel content = new JPanel(); //Create the panel to hold the label and text field
frame.getContentPane().add(content); //Add the panel to the frame
content.setLayout(new GridBagLayout()); //Set the panel layout to GridBagLayout
JLabel label = new JLabel("Enter Name:"); //Create a label
JTextField field = new JTextField(10); //Create a text field
JCheckBox checkbox = new JCheckBox(); //Create checkbox
GridBagConstraints constraints = new GridBagConstraints(); //Create a constraint
//Add the label with the defaults
content.add(checkbox, constraints); //Add the label using defaults
constraints.gridx=1;
content.add(label, constraints); //Add the label using defaults
//Add the field to show to the right of the label,
//and take up the rest of the leftover space.
constraints.gridx=2;
constraints.fill=GridBagConstraints.HORIZONTAL; //Stretch horizontally
constraints.weightx=1.0; //Take up the rest 1 of 1
content.add(field, constraints);
frame.pack();
frame.setVisible(true);
Saturday, August 16, 2003
Interesting problem.... JSP 1.2... who is right?
When I deployed it to WebLogic 8.1 it stopped working.
It seems that Resin allows you to use the import directive (<%@page import="foo.Boo") to import classes that get used by useBean (jsp:useBean class="Boo"), but Weblogic does not allow this, you have to always use the fully qualified classname with useBean even if you imported it (jsp:useBean class="foo.Boo"). I wonder who is right. Resin feels right.
I guess I should not be lazy and go look it up in the spec. and then report the bug to whoever is doing it wrong. Anyone know off the top of their head????????
Extreme programming: Process vs. culture
Extreme programming: Process vs. culture
Journal of Computing and Information Technology
The review was written by Hrvoje Bogunovic. I found his homepage, but alas there is not much there yet.
When I was up late working on the book at the coffee shop, I never dreamed someone in Croatia would write a review for it. We live in a small world. :)
--Rick Hightower
Friday, August 15, 2003
Fire Drill, Struts Best Practices
I finished my contribution to the second edtion of Mastering Struts by James Goodwill and Rick Hightower, which is now going to be printed under Wrox Professional Struts.
The last chapter I wrote was on Struts Best Practices, it covered the full gamut of things you need to do to use Struts on projects including StrutsTestCase, XDoclet for generation of validation.xml, transaction tokens to make sure a form only gets submitted once, when to use JSTL, how to write JSTL enabled tags, when to use Tiles, etc.
Wednesday, August 13, 2003
Books on Jakarta.... Crowbar Tech: Axis Book Dodgy
Crowbar Tech: Axis Book Dodgy
"
There are many good books on Apache's java software. At Crowbar, some of out favorites are:
Programming Jakarta Struts by by Chuck Cavaness
Java Development With Ant by Erik Hatcher, Steve Loughran
Apache Jakarta-Tomcat by by James Goodwill
And the best one, in our opinion is Java Tools for Extreme Programming: Mastering Open Source Tools Including Ant, JUnit, and Cactus by Richard Hightower, Nicholas Lesiecki.
Apache and Jakarta software is some of the best software available, commecial or not, according to our expert Crowbar analysts. The books on the subject should be of equally high quality. As for Wrox, here is a tip on how to create indexes.
"
Saturday, August 09, 2003
Contemplation
Some of this time was spent on the book, most of it was spent at work, and a little was spent working on an article.
I've got some good feedback from the Tiles chapter I wrote as follows:
Craig Pfeifer writes:
Rick --
I read your chapter on tilles and I enjoyed it. We're using tiles right
now on my project, and when we did our initial investigation/prototyping we
went through the exact same steps that your chapter takes the reader through,
so I think the flow and approach are dead on. (Wow... that is cool! Thanks)
Here are my comments (nits at best):
- in your code samples, you use the struts tag libraries where JSTL tag
libraries exist (logic, bean). Is there any reason to use the Struts
tags over JSTL in these samples? Also, you use scriplets in a couple of
places,
(Are you sure? I am quite sure that I never use scriplets. I do use expressions a few times.
Since you can write a Tile layout as a type of Visual component, it is probably okay to use scriplets in some instances. Even the Tiles examples do this.
You can use Tiles as a replacement for some custom tags. The examples that ship with Tiles use scriplets quite a bit. Think about Tile Layouts as another way to write a Custom Tags like thing.
Tile Layouts have a lot in common with the JSP 2.0 tag file. The same rules do not apply to Tile Layouts IMHO that apply to JSP files. You should be judicious not dogmatic.
It comes down to intent. If you intend on creating a site layout then you should not use scriptlets ever. If you are creating a reusable visual component than sciplets are okay.
Again, I don't use scriplets in the examples. At least I don't remember doing so.....
)
I'm a firm believer that scriplets are evil (mostly), is there a reason
that JSTL wouldn't work?
(In the examples you cite there is not reason JSTL would not work. I just did not want to make the asumption that they were using/knew JSTL. I think they should use JSTL whenever possible over using the equiv. Struts tags. We cover JSTL in another section of the book and we suggest using JSTL as you state. If I were writing this book in a year or two, when everybody uses JSTL than that would be a different story... I would not use bean:write, logic:iterate at all.... I think.)
- Since Tiles is just a tag library, I'm guessing that using JSPC in
your ant build to precompile your pages works the same as without Tiles.
Again, my current project makes heavy use of tiles and we find that the first
hit to each page is fairly hefty. Once the page is compiled it's not a big
deal, but that first step is a doozy. IMHO using JSPC is even more important
w/Tiles than without.
(I agree, but don't want to cover this in this chapter.)
- I think the sample JSPs would be more effective w/o the layout markup
(table formatting, fonts, styles). When I'm reading this chapter I don't
care about the HTML parts of the page. Keep all this stuff in the sample
code that you package and make available for download, but it just
clutters the page in the text.
(Hmmmm.... I see your point. I like the context though.)
- In the "Understanding and using Tile Scope" section there's a sentance
"The tiles scope is a similar scope to the page scope." This section
needs to be reworked for clarity and so you don't use the word 'scope' (even
though it is the proper term) 3 times in the same sentance. I think a
picture would go a long way in showing this.
(I have a really good editor. He will fix that. I'll send him your comment as well just to make sure.)
All in all I think it's a very solid chapter! There were some
grammatical issues here and there, and the look and feel of the headings doesn't do
much for me, but I was reading more for content and organization.
(My grammar sucks! I can write grammaticaly correct if I need to, but I cannot engage the right and left sides of my brain at the same time when I am writing a technical book, i.e., the creative part engages when I write. I can correct other people's grammar but have a hard time correcting my own, because I know what I meant. Thank God for Editors like Tim Ryan. Sometimes I will let a chapter sit for a month and then copy edit it. It makes more sense to me then. For now, I am relying on Tim Ryan.
The look and feel of the book will change quite a bit. It goes through a bunch of stuff. You are seeing it in its raw form.)
Craig
Friday, August 01, 2003
Tutorial offers fast track to component integration- ADTmag.com
"XDoclet allows you to tack on meta data to language features like classes, methods and fields using what looks like JavaDoc tags. It then uses that extra meta data to generate related files like deployment descriptors and source code," said Rick Hightower, director of development at eBlox and author of the developerWorks Web site's "Enhance J2EE component reuse with XDoclets" tutorial.
This, said Hightower, can cut out quite a bit of redundant coding.
Read more at: Tutorial offers fast track to component integration- ADTmag.com. Bummer that they got my company name wrong.
I work at Trivera Technologies. I am the CTO of Trivera Technologies not the Director of Development at eBlox (I used to be).
I was in Ohio for the last two days. The weather was really nice, and I had a good time.
Tutorial offers fast track to component integration- ADTmag.com
"XDoclet allows you to tack on meta data to language features like classes, methods and fields using what looks like JavaDoc tags. It then uses that extra meta data to generate related files like deployment descriptors and source code," said Rick Hightower, director of development at eBlox and author of the developerWorks Web site's "Enhance J2EE component reuse with XDoclets" tutorial.
This, said Hightower, can cut out quite a bit of redundant coding.
Read more at: Tutorial offers fast track to component integration- ADTmag.com. Bummer that they got my company name wrong.
I work at Trivera Technologies. I am the CTO of Trivera Technologies not the Director of Development at eBlox (I used to be).
I was in Ohio for the last two days. The weather was really nice, and I had a good time.
Monday, July 28, 2003
Late night... procrastination woes
Perhaps the root of the problem is a bad case of procrastination
. Anyway thanks for the good, timely advice. I've been at the coffee shop 5 times in the last week for my late night work sessions.
Friday, July 25, 2003
Erik Hatcher and Andy Barton are awesome.
It was a long chapter, about 40 pages, and he had comments all the way to the end of the chapter. He really took the time to review it.
Andy Barton just reviewed my Tiles chapter too. You Rock Andy! Thanks!
Tuesday, July 22, 2003
Driven by Demons
From http://www.washingtonpost.com/wp-dyn/articles/A28471-2003Jun24.html:
"All writers are vain, selfish and lazy, and at the very bottom of their motives there lies a mystery," he wrote in 1947. "Writing a book is a horrible, exhausting struggle, like a long bout of some painful illness. One would never undertake such a thing if one were not driven on by some demon whom one can neither resist nor understand."
Wow... I could not agree more. (Except the lazy part....)
Most great authors were drunkards or druggies. I either have to quit writing or don an addiction. I guess I never be great.
Writing is a mental mind screw for sure. It is addictive and painful. Every time I write, I always wonder, will this be read, will this be liked, will it be helpful.... my usual self confidense gives way to doubt and fear of critisism.
July 23rd
11:35 PM
It's my third night at the coffee shop. I've reached a new level of sleep deprived creativity. Did I mention that I am tired? I am considering going home to sleep. I got the monkey off my back by finishing the thing I needed to finish last night. Now I need to work on the next thing.
2:00 AM
I am out of here. Can't focus. Can't continue. Caffiene not working....
Catching up after my "praternity leave"
I am at the all night coffee shop again (it has been a month or so since I've been here). I seem to get the most work done from 9 PM to 3 AM. No one to bother me. No phone. No radio. No TV. No kids. No spouse. No email. No connection at the coffee shop means I wont cruise the Internet, read other people's blog, read technical articles, read email, read news groups, read postings, etc. and mistake it for getting something done. How do you keep up with it all?
Plenty of caffiene and my laptop means I will get a lot of work done tonight and this morning. I've already got a lot done. I can't wait to finish this project.
I wonder how much productivety is lost due to the Internet. I realize it increases the flow of information, but sometimes it seems like an overflow of information. I love and hate it at the same time. It is useful and a big distraction. God's gift and Satan's curse.
Blogs are funny, any tin horn technical dicator can pontifcate an opinion no matter how bad or how stupid (myself included of course). I love and hate blogs. I read some blogs this afternoon. I wish all blogs had a reply button. Given my tendency for distraction maybe its better that they don't. Technical pontification is the scurge of all that is good about blogs. On the other hand, I value blogs ability to give context to technology by getting people's opinions about various technolgies.
I now have an office in my garage. It has four walls and an air conditioner. (Air conditioner is a must in Arizona not a luxury.) All I need now is a espresso machine, small fridge (for milk), and a timer to turn off the Internet from 9 PM to 3 AM, and I will never go to the cofffee shop again.
Here I am writing my blog in notepad, because I am not connected. Apparently, if you try hard enough distractions can be found without the Internet. Excuse me while I go read the newspaper. LOL
I'll wrap this blog entry up at the end of the night.
.....
3:15 AM
The crowded coffee shop, now has just two customers left. The card players, socialites, college students have all came and gone. I didn't get as far as I wanted to (about 1/2 as far to be exact), but the project is moving in the right direction. I had to switch to green tea and bottled water after my first vanilla latte lest I spend more time in the restroom than writing. I am going home to get some shut eye.
Yes I realize email, phones and communication with the outside world is important, but sometimes all you need is a laptop and some peace and quiet.
Monday, July 21, 2003
EJB CMP CMR
" I'm thinking of Entity EJBs here, but the same is true to some extent with JMS and JDO, where all of the really useful pieces for O/R mapping are optional. I accidentally insulted Rick Hightower Thursday night when he was talking about successfully using Entity Beans in a project by saying that his domain model must have been simple…. Sorry about that. What I meant was that a reasonably sized project couldn't use Entity beans successfully without using vendor extensions, and in fact he was. "
First, it was on purpose. :)
Second, I was not offended my skin is pretty thick.
Third, the same arguments can be made against JDO or any other OR mapping solution.
Fourth, I have ported EJB CMP CMR applications to more than one vendors solution.
Fifth, At the time EJB CMP CMR was available, and JDO was not.
Sixth, I am going to try Hibernate on my next green field application.
Jason put your picture in your blog. I can't remember who was who.
Wednesday, July 16, 2003
The reason I changed the title of my blog....
" Announcing Rick Hightower 2.0......
His name is Richard Matthew Lucas Hightower Jr. We are going to call him Lucas.....
(I know... I know.... "Luke I am your father..... Use the force Luke")
Wednesday, July 09, 2003
What skills are marketable
Java 3365
Perl 989
Python 58
Ruby 5
C 2659
C# 500
Struts 162
WebWork 3
WebLogic 554
WebSphere 770
Tomcat 132
Resin 7
Orion 1
SQL 4082
Oracle 3671
JBoss 43
TogetherSoft 20
Eclipse 17
JBuilder 66
WSAD 67
Web Services 1388
JSP 673
ASP.Net 12
EJB 3365
Velocity 37
Ant 74
XDoclet 3
SOAP 207
PORTAL 761
Tapestry 6
The surprise here is how little ASP.Net gets compared to JSP. Now this is not scientific (as if)..... just because Struts gets more hits than WebWork does not mean it is better.... it just means it is a more marketable skill (I suppose). EJB (bitter or not) is still very marketable (more so than JSP).
Monday, July 07, 2003
Bitter EJB and extreme sports
Amazon.com: Books: Bitter EJB
This is a very thought provoking book. I am about 1/2 done with it. I can already recommend it to all those that will be doing or are thinking about doing EJB development.
Every chapter starts with a short story about the author(s) endeavors in extreme sports.
At first, I found the short stories distracting. As I continued to read the book, I found that they are a nice break from the material that are easily ignored if I choose not to read them.
I am not much of an extreme sports advocate, if I wrote a book like this.... the chapters would start more like this....
"It was a Sunday night, and it was my turn to do the dishes. I know I had to mentally prepare.... "
or
"I was sitting on the couch watching TV. I wanted to change the channel, but this would require looking for the remote... I ended up watching three hours of infomercials instead of finding the remote."
Actually, I did go snowboarding once.... my posterior hurts just thinking about it. My idea of an extreme sport is walking around the block with my kids or playing wiffle ball with my son and daughter. After reading this book, I just might put air into my mountain bike tires and ride around.
Wednesday, July 02, 2003
Observation about Tiles and sharing attributes from tile layout to tile
When inserting one tile into a page layout tile, The tile that is getting inserted into the page layout tile does not share the variables of the page layout tile scope. They each get there own tile scope.
Thus if the page layout tile is passed a title attribute that title attribute is not passed to the tile (e.g., header.jsp) that dispalys the header. In order to pass the variable to the header.jsp. I must use the tiles:put.
This is because the tiles:insert creates a new component context for the inserted tile (I checked the code and create a debug util to prove this). Thus there is a one to one relationship between component contexts and tiles. (Component context = tile scope for the tile).
The tiles:put allows me to put variable from various scopes if I leave the scope blank it searches all scopes including tile scope (i.e., component context).
Thus to move a variable from a page layout to a tile I would do this:
<tiles:insert attribute="header" ignore="true">
<tiles:put name="title" beanName="title"/>
</tiles:insert>
I just installed the Google Toolbar... now I can blog about sites that I visit... even quicker.
Debugging Util for Struts apps
I think I have written this same utility several times over the years.....
Here it is..... (maybe I wont loose it this time)....
/*
* Created on Jul 2, 2003
*
* To change the template for this generated file go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
package util;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.JspException;
import org.apache.struts.taglib.tiles.ComponentConstants;
import org.apache.struts.tiles.ComponentContext;
import java.io.IOException;
/**
* @author rhightower
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
public class DebugUtil {
public static void listScope(PageContext context, int scope) throws JspException, IOException{
JspWriter out = context.getOut();
switch (scope){
case PageContext.PAGE_SCOPE :
out.println("--- Page Attributes ---
");
break;
case PageContext.REQUEST_SCOPE :
out.println("--- Request Attributes ---
");
break;
case PageContext.SESSION_SCOPE :
out.println("--- SESSION Attributes ---
");
break;
case PageContext.APPLICATION_SCOPE :
out.println("--- APPLICATION Attributes ---
");
break;
}
Enumeration enums = context.getAttributeNamesInScope(scope);
while(enums.hasMoreElements()){
String name = (String)enums.nextElement();
Object value = context.getAttribute(name, scope);
printNameValueType(name, value, out);
}
out.println("---------------------------
");
}
private static void printNameValueType(String name, Object value, JspWriter out) throws IOException{
out.println(name + " = " + value
+ " type (" + value.getClass().getName()+ ") " +
"
");
}
public static void listParameters(PageContext context)throws JspException, IOException{
JspWriter out = context.getOut();
Map map = context.getRequest().getParameterMap();
Iterator iter = map.entrySet().iterator();
out.println("--- Request Parameters ---
");
while (iter.hasNext()){
Map.Entry next = (Map.Entry) iter.next();
if (next.getValue() instanceof String){
out.println(next.getKey() + " = " + next.getValue() + "
");
}
else if (next.getValue() instanceof String[]){
StringBuffer buf = new StringBuffer(100);
String[] values = (String[])next.getValue();
buf.append("{");
for (int index = 0; index < values.length; index++){
buf.append(values[index]);
buf.append(",");
}
buf.append("}");
out.println(next.getKey() + " = " + buf.toString() + "
");
}
}
out.println("--------------------------
");
}
public static void listTileScope(PageContext context) throws JspException, IOException {
JspWriter out = context.getOut();
ComponentContext compContext = (ComponentContext)context.getAttribute( ComponentConstants.COMPONENT_CONTEXT, PageContext.REQUEST_SCOPE);
out.println("--- TILE Attributes ---
");
if (compContext!=null){
Iterator iter = compContext.getAttributeNames();
while(iter.hasNext()){
String name = (String)iter.next();
Object value = compContext.getAttribute(name);
printNameValueType(name, value, out);
}
}else{
out.println("--- TILE Attributes NOT FOUND ---
");
}
out.println("---------------------------
");
}
public static void debug(PageContext context) throws JspException, IOException{
JspWriter out = context.getOut();
out.println("
--------------------------
");
out.println("---------D----------------
");
out.println("----------E---------------
");
out.println("-----------B--------------
");
out.println("------------U-------------
");
out.println("-------------G------------
");
out.println("--------------------------
");
listTileScope(context);
listScope(context, PageContext.PAGE_SCOPE);
listScope(context, PageContext.REQUEST_SCOPE);
listScope(context, PageContext.SESSION_SCOPE);
listScope(context, PageContext.APPLICATION_SCOPE);
listParameters(context);
}
}