Thursday, August 28, 2003

Looking for something else and I ran into this....

Mastering Tomcat...

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’d like to see Struts play nice with JSTL i18n support.

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)

From Nightly build....


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 told Erik about my new Validator rule, and he told me to try to contribute it. Erik is my open source mentor.

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)

I wrote about the JSTL validator that I created that I though was better than requiredif and validatewhen, and someone wrote me an email asking what requiredif and validatewhen were. (see my blog entry about the JSTL validator too)

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 sitting at lunch eating a coney at Skyline in Cincinnati (not my favorite YUCK).... I from Tucson AZ, and I can't understand how Skylines draws such a crowd.

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!

dining011002

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!)

What I don't like about GridBagConstraints....

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?

I ran into a werid problem. I wrote a JSP/Struts application and deployed it to Resin 2.1. But....
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

Erik Hatcher and I use to work with Ryan Ripley at eBlox/PromoFuel. I need to read his article....

Extreme programming: Process vs. culture

Journal of Computing and Information Technology

I just recieved a copy of the Journal of Computing and Information Technology from the University Computing Centre in Zagreb, Croatia. They reviewed the book that me and Nick wrote (Java Tools for Extreme Programming). It was a nice review. And, they were kind enough to send us several copies along with the Journal that has the review in it.

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

Started this week in total fire drill mode. Somehow it has managed to be a good week. I've spent a lot of time tihs week with WebLogic 8.1.

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

I saw this and I could not help linking to it. Thanks by the way... you made my day.
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

I just realized I worked 20 of the last 24 hours. This week I put in something like 75 hours. More like a 100 if you count travel time (planes).

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

I am quoted in ADT Programmer's Report Weekly wrt to XDoclet (Tutorial offers fast track to component integration- ADTmag.com). Here is a small snip:

"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

I am quoted in ADT Programmer's Report Weekly wrt to XDoclet (Tutorial offers fast track to component integration- ADTmag.com). Here is a small snip:

"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.