Genschaw's Tech Blog

Java, JEE, Spring, JSF, Struts, Maven

Monday, October 27, 2008

CSS Day 4

Thursday started with a keynote presentation titled "A Straw Model for the Future of Open House". He basically talked about how more and more, are providing open source products and offering paid support. This is even becoming true for big companies (IBM, JBOSS/RedHat, etc).

Next was "Applying Flash to Java: FLEX and OpenLaszlo". These are frameworks which allow you to build Flash-based java web 2.0 applications. FLEX is open source with a rich class library, with optional paid support. Compiles code + xml to *.swf (flash) files. Advantage is broswer-independence and "flashiness". There is a free eclipse plugin and a commercial "Flex Builder" IDE. Drawbacks of flash:
1) not searchable/linkable/bookmarkable (but this may improve)
2) Flash itself is not open source
3) No real competitors
4) no 64-bit support
5) mobile apps
6) loading performance

After lunch was "Real World Groovy". This session demonstrated the power of the groovy scripting language and how you could use it to add scripting functionality to existing applications. Get the groovy plugin for eclipse. I think groovy is real good for the right tasks, one-off or utility types of functions. Very dynamic and reflective language, but comes with a performance penalty over straight java. Not appropriate for mission-critical enterpise apps that must perform well. Best Book "Groovy in Action".

Next was "Performance Engineering from Scratch". This was got into some pretty hardcore analysis of various algorithms, specifically sorting ones. Luckily, the common ones used in java are implemented appropriately (Arrays.sort). One thing I took away is that often times a TreeMap/Set will perform better than a HashMap/Set, especially with large datasets and large strings. This is because the former uses "hashCode" which must evaluate each character, while the latter uses "compareTo" which can terminate earlier (first non-matching character). Share StringBuffer.append(char[20000]).append(char[2]) anecdote.

Finally was "Open Web File System". This showed how to use various open web file storage sites and how to mount them to your machine using WebDAV. Not sure I'll ever use this in my job, but it was interesting.

CSS Day 3

Wednesday started off with a session titled "Put your feet up and take a RESTful approach". This again demonstrated the details of RESTful web applications, and how they can support Web 2.0 along with AJAX and JSON. REST is not a technology or standard, merely an architectural style or design pattern. Rather, it is built on standards (HTTP, URI, XML, mime types) and standard HTTP methods (GET, PUT, POST, DELETE). Allows for less dependencies on vender software/middleware and spec levels. Web Services still have their place, well suited for computer-to-computer communication. REST is more appropriate for human-to-computer (straight html) or browser-to-computer (ajax + JSON). Becareful of the data exposed.

Next was "Becoming a JavaScript Wizard". One thing I took away from this is that it's good we are using prototype and scriptaculous, they smooth out browser differences make things easier in general. Remember separation of concerns - structure (data)/ presentation (css) / behavior (js). All javascript in a *.js file. Use namespaces! See Douglas Crawford, recognized as the javascript guru. Move away from DOM 0 events (onlick attrs), this ties the structure to the behavior, instead use DOM 2 (prototype: Event.add(*)). See ExtJS library.

After lunch was "What OO Doesn't address". This session spoke to what OO does and doesn't provide. OO is good because it addresses maintenance, quality, reliability and "writeability". Allows to package code in a way that makes sense, keeping things apart that change independently, and things together which change together. Allows software to be resilient to change, not resistant. Security and performance are not addressed. Gave some tips to help. Reduce the scope of syncronized and transactional code. Beware of "medium-lived" objects, the garbage collector is optimized for short and long-lived objects, mediums result in more page faults and slower performance.

Next was "Building Rich Internet Applications with Appcelerator". Appcelerator is an ajax-based web 2.0/RIA framework (ala GWT or FLEX). It uses a lot of custom attributes on standard html elements, so you don't need to know a lot about javascript. It seems like a good fit for smaller shops or startups where there is not a lot of seperation or expertise between layers of the application. Someone with a high-school diploma could probably download the framework and get something working pretty easy. It was compared with other RIA frameworks including Adobe FLEX and Google Web Toolkit. SOFEA and SOUI were mentioned. Appcelerator does not have as wide of a user base, but documentation is good. Is not a full stack meaning it does not have a library for implementing the server side (ala database). Skyblox and snappshot are two example sites built on appcelerator. His advice when evaluating web frameworks was to have a few frameworks available, some are better for certain apps. He suggested trying several of them and eliminate rather than include.

The final session was "Service Validation, Incremental and Iterative Development". This session talked about incremental and iterative development, how you must have trust between the business and IT. Do "just enough" requirements and design to get started, flushing out through iterations. Cheaper to catch bugs sooner than later. Don't "gather" requirements, "elicit" them, it is a discussion. ITIL "V-Model" was discussed. Need a "Service Portfolio".

Wednesday, October 22, 2008

CSS Day 2

Tuesday we got an early taste of winter as it snowed an inch or so here. The first session of the day was "Efficient Enterprise Builds with Apache Maven". I learned some of the upcoming features in the upcoming release of maven. One that I really have been waiting for is being able to include pom.xml snippets (rather than only extending). They call this feature "mix-ins" and looks like they will eventually replace "profiles". I also learned that we should revisit the way we manage our repositories at GL. Also remind me to talk to management about making m2eclipse part of our standard RAD install. I also learned more about creating archetypes and how they can help us bootstrap new projects.

Next was "Mastering JavaServer Faces". The first part was mostly basics and a review for me. The rest was a focus on third-party libraries which are really needed in order to unlock the power of JSF. I was glad to see our choice of facelets and RichFaces re-affirmed. These were two of the presenters most recommended libraries. I didn't know a whole lot about RichFaces and came out extremely impressed, especially with the built-in ajax support, as ajax can be tricky with JSF. RichFaces handles it all for you with a rich set of custom tags/components. I think we can use it to enhance the Branded MPN user experience dramatically. Also discussed were offerings from apache including the MyFaces JSF implementation as well as the component libraries Tomahawk, Trinidad, & Tobago. There is a bit of overlap between these 3 libraries which can make choosing one difficult. Again, the presenter suggested turning to RichFaces first, which was comforting as it is already approved for use at GL. Facelets was recommended over tiles for JSF templating support, also comforting as it is used in the Branded MPN.

After lunch was a mostly philosophical presentation titled "Object Orientation, Domain Driven Design and the Honour of the Programmers' Guild". Refactoring is absolutely essential in order to make OO work. Development cycles should use a "wave" approach where the first wave is the core development and implementation of features and the second wave is a refactoring phase to clean up the code and improve the design to align with the business/domain concepts. Code should be written consistently with the terminology of the business/domain and it is a collaborative effort with the business area/clients. I think we do an okay job here but collaboration with the business areas could be better. To paraphrase the presenter:
"The business area knows the concepts of the business, but not necessarily how to logically group and implement the features, and the effect of feature requests on the rest of the system. This is the expertise of the development team. It is important for business and development to be on the same page, so the business concepts are reflected appropriately in the code. As the development team implements features, new logical concepts may manifest themselves, and it is important to share/agree these concepts with the business area so we all are using the same glossary". Refactoring can be harmful however, if it is done without a full logical understanding of the problem domain (Milking a cow analogy). He finished with a story about a guy who worked on the dominant product in the industry (MARC, I think physics related). Again and again, he was not allowed to refactor, became increasingly frustrated and eventually quit. He subsequently built a new, better product (ABAQUS) which ended up replacing the former as the dominant, standard application in the industry. Developers must stand up for what they feel is right, and management should respect those in the code.

Next was a session titled "Pragmatic REST" which was my first hardcore exposure to the concepts and implementation of a REST-ful web application. I learned some of the best practices and common anti-patterns.

Finally was a presentation "Domain Driven Design and the power of Value Objects". GL terminology: VO's are really what he calls DTO's (J2EE patterns book used bad terminology and was eventually revised). Value objects should be business objects that reflect the domain model, encapsulating data and behaviors to improve API clarity and to swallow computational code, thus improving service implementation clarity, and reuse (Phone number example).

Wednesday's agenda includes more REST, Cloud computing, development process improvement/refactoring, SOA, and agile development.

Monday, October 20, 2008

CSS Day 1

We made it to the conference on Sunday afternoon, checked in, and still had time to watch most of the second half of the Packers win vs the Colts. There was a nice reception Sunday night with a buffet and lots of food. My first time eating buffalo...tastes like beef.

Today's conference opening keynote focused on the enterprise of the future and characteristics of those which are most likely to succeed, especially in the current economic climate and specifically those in the finance world. A technology outlook was presented which depicted the future of the industry, reinventing the way computer systems are built, utilizing multi-processor computing grids, "cloud" computing and the use of social and data networking for the enterprise (facebook, linkedin, etc.). The ability to do business anywhere, anytime, and in real-time are and will continue to be prevalent. We are in an ever-increasing service-oriented economy, and enterprises are innovating their business models with a collaborative approach rather than outsourcing. As this continues, SOA governance is important.

The first presentation today, I saw a presentation about Google App Engine which allows for developing applications and deploying and running those apps on Google's infrastructure. It seems to be mostly geared towards start-ups and providing ajax based services. It currently supports python based apps but more languages will be supported soon (including java?). Next was a presentation titled "Laptop Linux" which gave tips, tricks and lessons learned while migrating completely from a Windows world to a Linux/Open Source environment. After that I saw a presentation titled "Pimp my webapp (with Google Web Toolkit)". GWT is definately a very cool, easy to use, cross-browser compatible technology that GL should consider, especially with the emergence of web 2.0/RIA. It is far easier than the way we have been implementing ajax-based webapps. Multi-browser support is built-in, and client side code is written in java, while GWT "compiles" it to javascript. No need to be a javascript wizard, GWT does it all for you. It also scales better than other apps because only data is transferred over the wire. It is anticipated that by 2010, 60% of all new webapps will be RIA. Finally was a presentation about what's coming up in Spring 3.0. The focus is support for REST-ful service implementations, less xml/more annotations, a robust expression language, and the potential merge of Spring MVC and webflow. It is however behind schedule, and being developed "behind closed doors" which has cause for concern among the open source community, especially with recent announcements from springsource regarding the availability of maintenance releases to only those customers paying for support. JEE5 has made great strides in closing the gaps that initially made J2ee cumbersome and led to the emergence of light-weight frameworks such as spring. In some ways, JEE5 could now be considered more light-weight than spring (jee.jar is smaller than spring.jar). As such, the value-add of spring has diminished, mostly left to a robust DI implementation. Google Guice is something to look into, focused on a simple easy to use DI framework, while leaving the JEE container for the web framework (JSF), remoting (JAX-WS), persistence layer (JPA) and transactions (EJB).

Tomorrows agenda includes JSF, more REST, maven, domain-driven design and agile development. Until then...

Friday, October 17, 2008

Colorado Software Summit

I'll be at the Colorado Software Summit next week. Check back for updates.

Monday, September 8, 2008

Eclipse XML Catalog entry for DTD or XSD contained in jar

This is useful to fix the code-assist feature, when (for example, Facelets) the URI for a schema you are dealing with does not exist at its given location.

When defining a facelets taglib.xml, the DOCTYPE will be:


<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">


However, "http://java.sun.com/dtd/facelet-taglib_1_0.dtd" returns a 404. As a result, code-assist is not available when editing the file. The DTD in question is packaged in the facelets jar. It is possible to tell eclipse to get the DTD from the jar instead of the actual web resource.


  • Go to Window...Preferences.

  • Expand "Web and XML" and select XML Catalog (the actual names here may vary depending on version of Eclipse).

  • Select "User Specified Entries" and click "Add...".

  • Provide the following


    Location:
    "jar:file:T:/Edc/incubator/m2-repository/com/sun/facelets/jsf-facelets/1.1.14/jsf-facelets-1.1.14.jar!/facelet-taglib_1_0.dtd"
    Key Type:
    "Public ID"
    Key:
    "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"



Note in my case I'm pointing to a jar in a maven repository, but you can also point to a jar in your workspace.

Thursday, May 8, 2008

Using shale commons-validator with facelets

This entry describes how to integrate the Shale commons-validator tags with facelets. These tags include:
  • commonsValidator
  • validatorVar
  • validatorScript

For example:

...
<h:form onsubmit="return validateForm(this);">
...
<label for="firstName"
value="#{bundle['person.firstName']}*" /><br />
<h:inputText id="firstName" value="#{person.firstName}"
size="22" maxlength="20">
<val:commonsValidator type="required"
arg="#{textBundle['person.firstName']}" client="true" server="true" />
<val:commonsValidator type="maxlength" maxlength="20"
arg="#{textBundle['person.firstName']}" client="true" server="true" />
<val:commonsValidator type="mask"
arg="#{textBundle['person.firstName']}" client="true" server="true">
<val:validatorVar name="mask" value="#{validationBundle['regexp.personName']}" />
</val:commonsValidator>
</h:inputText>
...
<val:validatorScript functionName="validateForm" />
</h:form>
...

First, you must create a facelets taglib file to tell facelets how to interpret these tags. Within the taglib file, you will refer to specific facelet TagHandler implementation classes that you will provide.



shale-validator-taglib.xml

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
"http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>

<namespace>http://shale.apache.org/validator</namespace>

<tag>
<tag-name>validatorScript</tag-name>
<component>
<component-type>org.apache.shale.ValidatorScript</component-type>
</component>
</tag>

<tag>
<tag-name>commonsValidator</tag-name>
<handler-class>net.genschaw.jsf.facelets.CommonsValidatorHandler</handler-class>
</tag>

<tag>
<tag-name>validatorVar</tag-name>
<handler-class>net.genschaw.jsf.facelets.CommonsValidatorVarHandler</handler-class>
</tag>

</facelet-taglib>

Save this file in your webapp, commonly under /WEB-INF. The <namespace> element is defining the namespace you will use for prefixing in your facelets templates.
For example:

<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jstl/core"
xmlns:val="http://shale.apache.org/validator">
...
...
</html>

The first <tag> element tells facelets to create a ValidatorScript component when it encounters a validatorScript tag. This component is defined in Shale's faces-config.xml.

The second <tag> element tells facelets to invoke a TagHandler when it encounters a commonsValidator tag. The tag handler is a class you need to implement (see below) to create a CommonsValidator instance and attach it to the associated component.

Finally, the third <tag> element tells facelets to also invoke a TagHandler when it encounters a validatorVar tag. This handler needs to expose the name/value pair in the current FaceletContext. The CommonsValidatorHandler will subsequently apply the variable(s) to the CommonsValidator it creates.

CommonsValidatorHandler

package net.genschaw.jsf.facelets;

import java.io.IOException;
import java.util.Map;

import javax.el.ValueExpression;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.validator.Validator;

import org.apache.shale.validator.CommonsValidator;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.tag.MetaRuleset;
import com.sun.facelets.tag.MetaTagHandler;
import com.sun.facelets.tag.Metadata;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagConfig;
import com.sun.facelets.tag.TagException;

/**
* Facelets TagHandler for "commonsValidator" tag.
*
* @author Shane Genschaw
*/
public class CommonsValidatorHandler extends MetaTagHandler {

/**
* Set validatorVar tag variables on commons validator.
*
* @see com.sun.facelets.tag.Metadata
*/
public static class ValidatorVarMetadata extends Metadata {

/**
* @see com.sun.facelets.tag.Metadata#applyMetadata(com.sun.facelets.FaceletContext, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public void applyMetadata(FaceletContext ctx, Object instance) {
Map validatorVars = (Map) ctx.getAttribute(CommonsValidatorVarHandler.KEY);
if (null != validatorVars) {
CommonsValidator v = (CommonsValidator) instance;
v.getVars().putAll(validatorVars);
ctx.setAttribute(CommonsValidatorVarHandler.KEY, null);
}
}
}

private final TagAttribute binding;

private String validatorId = "org.apache.shale.CommonsValidator";

/**
* @param config
*/
public CommonsValidatorHandler(TagConfig config) {
super(config);
this.binding = this.getAttribute("binding");
}

/**
* @see com.sun.facelets.FaceletHandler#apply(com.sun.facelets.FaceletContext,
* javax.faces.component.UIComponent)
*/
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException {
if (parent == null || !(parent instanceof EditableValueHolder)) {
throw new TagException(this.tag,
"Parent not an instance of EditableValueHolder: " + parent);
}

// process validatorVar tag(s), if present
if (nextHandler != null) {
nextHandler.apply(ctx, parent);
}

// only process if it's been created
if (parent.getParent() == null) {
// cast to a ValueHolder
EditableValueHolder evh = (EditableValueHolder) parent;
ValueExpression ve = null;
Validator v = null;
if (this.binding != null) {
ve = this.binding.getValueExpression(ctx, Validator.class);
v = (Validator) ve.getValue(ctx);
}
if (v == null) {
v = this.createValidator(ctx);
if (ve != null) {
ve.setValue(ctx, v);
}
}
if (v == null) {
throw new TagException(this.tag, "No Validator was created");
}
this.setAttributes(ctx, v);
evh.addValidator(v);
}
}

protected Validator createValidator(FaceletContext ctx) {
if (this.validatorId == null) {
throw new TagException(
this.tag,
"Default behavior invoked of requiring a validator-id "
+ "passed in the constructor, must override ValidateHandler(ValidatorConfig)");
}
return ctx.getFacesContext().getApplication().createValidator(
this.validatorId);
}

// alias the minlength and maxlength attributes
@SuppressWarnings("unchecked")
protected MetaRuleset createMetaRuleset(Class type) {
MetaRuleset metaRuleset = super.createMetaRuleset(type).ignore(
"binding").alias("minlength", "minLength").alias("maxlength",
"maxLength").add(new ValidatorVarMetadata());

return metaRuleset;
}

}

CommonsValidatorVarHandler

package net.genschaw.jsf.facelets;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.el.ValueExpression;
import javax.faces.component.UIComponent;

import com.sun.facelets.FaceletContext;
import com.sun.facelets.tag.TagAttribute;
import com.sun.facelets.tag.TagConfig;
import com.sun.facelets.tag.TagHandler;

/**
* Facelets TagHandler for "validatorVar" tag.
*
* @author Shane Genschaw
*/
public class CommonsValidatorVarHandler extends TagHandler {

/** Key under which variable map is stored in FaceletContext. */
public static final String KEY = "validatorVars";

// possible attributes
private final TagAttribute name;
private final TagAttribute value;

/**
* @param config
*/
public CommonsValidatorVarHandler(TagConfig config) {
super(config);
this.name = getRequiredAttribute("name");
this.value = getRequiredAttribute("value");
}

/**
* @see com.sun.facelets.FaceletHandler#apply(com.sun.facelets.FaceletContext,
* javax.faces.component.UIComponent)
*/
@SuppressWarnings("unchecked")
public void apply(FaceletContext ctx, UIComponent parent)
throws IOException {
String nameStr = this.name.getValue(ctx);
ValueExpression veObj = this.value
.getValueExpression(ctx, Object.class);
if (null != veObj) {
Map validatorVars = (Map) ctx.getAttribute(KEY);
if (null == validatorVars) {
validatorVars = new HashMap();
ctx.setAttribute(KEY, validatorVars);
}
validatorVars.put(nameStr, veObj.getExpressionString());
}
}

}

The last step is to add a configuration parameter in your web.xml file to tell facelets to load you're new taglib.

<context-param>
<param-name>facelets.LIBRARIES</param-name>
<param-value>/WEB-INF/shale-validator.taglib.xml</param-value>
</context-param>

Additional Resources