Wednesday, March 25, 2009

What's up with 0.0 not being mapped in Struts 2.1.6?

Recently converted to Struts 2.1.6, and I found a small problem. There were double values displaying in my JSP textfields as 0.0. When those values were submitted to my action which had a setQuantity (double quantity), I was receiving OGNL Exceptions saying that the method setQuantity([Ljava.lang.String;)] did not exist. Something similar to this:

[java.lang.NoSuchMethodException: setQuantity([Ljava.lang.String;)]  
at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:823)
at ognl.OgnlRuntime.setMethodValue(OgnlRuntime.java:964)
at
ognl.ObjectPropertyAccessor.setPossibleProperty(ObjectPropertyAccessor.java:75)
at
ognl.ObjectPropertyAccessor.setProperty(ObjectPropertyAccessor.java:131)
at
com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.setProperty(ObjectAccessor.java:28)


Well of course it did not exist, it was a double I was submitting. I wanted nothing to do with Strings on this field.

It turns out that this is a known issue with the xwork-2.1.2.jar file. So I was able to find the xwork-2.1.3.jar file from here:
http://jira.opensymphony.com/browse/XW-676

Once I added this to my project, the problem was solved and things are working nicely again. Enjoy!

Thursday, March 5, 2009

Formatting Numbers with Struts 2

I just wasted about 4 hours trying to figure out how you can format a number in a textfield with Struts 2. The only explanation was at http://struts.apache.org/2.0.14/docs/formatting-dates-and-numbers.html
I found was to make my <s:textfield> tag look like this:


<s:textfield key="orderItem.price"
value="%{getText('format.number',{'orderItem.price'})}" />

In this instance format.number refers to an entry in your package.properties file (NOTE: You actually should call this file package.properties. 'package' does not refer to the actual name of your package.) Inside this package.properties file you need an entry that looks similar to this

format.number= USD{0,number,##0.00}

which will output the number 1500.0 like: USD 1500.00

Anywho, there are several ways to define a formatting properties file, but for eases sake, just place the package.properties file inside the directory that your java action is. If I have an action org.james.actions.ViewPurchaseOrdersAction.java. Then my package.properties file would belong in org.james.actions. Now if you want your package.properties file to apply to all your actions, you can adjust the placement of the file, placing it higher in the package hierarchy. Basically Struts 2 will hunt down your package.properties file for you. The choices you make all depends on how tied to your actions your formatting should be.

Back on track. The key attribute of the above tag does something that I'm too lazy to look up. I didn't need it, we'll pass over. The shady thing though, is the value attribute. Using the above style for the value attribute, I was not able to get my formatted price to display.

After exhausting my patience trying all kinds of different things I started trying random things, and eventually got the following to work (Notice that the % and quotes are not inside the purchaseOrder.amount argument):

<s:textfield name="amount" theme="simple" value="%{getText('format.number',{orderItem.price})}" />

I'm not sure if this is because I'm on Struts 2.1, while the tutorial I took that snippet from is Struts 2.0, whether I just implemented something improperly, or whether that code snippet is just flat out wrong.

Either way I don't really care. My code works now, and I can move onto the next problem.
If the Struts 2 example from the official site isn't working for you, try mine.





Tuesday, March 3, 2009

Struts 2's Select Tag

Struts 2 provides a lot of useful tags that you can use in your jsp pages, to help simplify your html/java code.

One in particular that is fairly complex and requires explanation is the <select> tag.

Typical html select tags require you to specify the list of values one by one, creating potentially lengthy code. It's relatively inflexible and workarounds are usually abundant to get it to behave how you want.

The Struts 2 <s:select> tag however, provides nearly everything you could need to have fully functioning select dropdown functionality.

The attributes I use are headerKey, headerValue, list, listValue, and listKey.
One by one, headerValue allows you to tell your dropdown to initially display a message to your user. For example, if you want to tell your user, "Please select an employee", you can simply use that as the headerValue, and that will display as the very first option in your dropdown list.

The headerKey attribute assigns a value to the headerValue attribute. My headerKey is typically -1. Using this, when a page is submitted, I can easily ensure that a legitimate value has been selected, by ensuring the headerKey != -1.

list, tells the Struts tag what variable contains the list that you want to appear in the dropdown. The value you use for the list attribute must be iterable. In my Java action, I provide an ArrayList object that contains the values I want to be in my dropdown list. So if I have an Employee object, with getters and setters for employeeId and employeeName, and within my ArrayList called employeeList that has my Employee objects, I can specify that my list attribute is employeeList.

Next up is the listValue and listKey attributes. They work together. The listValue is what actually gets displayed in the dropdown list. Not the list that is iterated over, but the actual words themselves that appear. So using the employee example, I'd want the user to see the names of employees in my dropdown, so I'd specify my listValue="employeeName".

The listKey attribute indicates what request parameter value should be passed back to my action upon submission. For this example I'd make listKey="employeeId". But if you wanted to pass the name that was selected, you'd simply make listKey="employeeName".

Apart from the basic name and value attributes, which are self explanatory, you now have a fully functional dropdown list in your jsp, simply by using:

<s:select name="myEmployee" list="employeeList" headerKey="-1" headerValue="Please Select an Employee" listValue="employeeName" listKey="employeeId" />

And there you have it. The power of the Struts 2 <s:select> tag semi-de-mystified.

Tuesday, February 24, 2009

Jar'ing Files to Use With Eclipse

Assuming you have your PATH set properly on your machine, JAR'ing files is relatively easy. But I think I screwed something up at first. I first JAR'd .java files together using the command jar cvf journyxapi.jar *, which took everything in my jxapi_pkg directory and jar'd it up.

This of course did me no good whatsoever, since I need the actual class files in the jar for my application to work. So I made class files of everything in jxapi_pkg and re-ran the same command.

When I imported this JAR file into my eclipse project, I still was not able to import files in there. It was like the file didn't exist in eclipse.

So I finally bundled both my class files, and java files together in a directory, and then ran the command jar cvf journyxapi.jar jxapi_pkg.

This worked like a charm when I imported it into my project. I'm not sure if I'm just ignorant when it comes to jarring or what, but this is what I had to do to get my jar file behaving.

The Battle With cacerts and HTTPS

While trying to work through the tutorial to Journyx's Web Services (jxapi), all kinds of crap started going wrong. First off, I needed to generate the Java Code from Journyx's WSDL.

The URL that had the WSDL file was under https. When I tried to do a WSDL2Java Axis command from my command prompt, I started getting back all kinds of errors. The first problem was that when you're running Axis, all of the
/lib jar files, need to be in your classpath. I fixed this by explicitly setting the SYSTEM's Environment Variables to include all of the jar files axis.jar, axis-ant.jar, commons-discovery-0.2.jar, commons-logging-1.0.4.jar, jaxrpc.jar, log4j.jar, log4j-1.2.8.jar, saaj.jar, wsdl4j-1.5.1.jar.

Problem 1 down. Next, I had to add the xercesImpl.jar file (from Xerces) to the class path. Problem 2 down. Finally I had to add the mail.jar and activation.jar files into the CLASSPATH. I had to go and download all this stuff from the Java 6 EE SDK from Sun's website. Both mail.jar and activation.jar are in
/lib. I downloaded Java 6 EE from http://java.sun.com/javaee/downloads/index.jsp. I downloaded the Glassfish Java EE + JDK one.

So all the classnotfound exceptions coming from the DOS window were stopped, but instead I was getting a

java.security.cert.CertPathValidatorExcep

tion: basic constraints check failed: pathLenConstraint violated - this cert must be the last cert in the certification path


This was a bummer. I read various sites, and the first issue was that the CA Certificate that Journyx was using, was not located in my cacerts file. Basically, CA Certificates seems to be what https uses to communicate. Both the client (my code), and the server (their code), have to have this certificate included as a trusted certificate. I think that in order to make the certificate trusted, you have to place it in java's cacerts file. THIS FILE FOR ME WAS LOCATED IN 2 SEPERATE PLACES. One was at /lib/security. The other was at /jdk/jre/lib/security. This fact is important. Be warned.


Anywho, in order modify the cacerts file, you have to use Java's keytool. I hit the WSDL address directly from the browser and was able to see the WSDL in the browser. In the browser, from the WSDL, if you double click the lock icon at the bottom of your browser, and click View Certificate, you can actually see what certificates are being used by Journyx. There were 3, but I only exported the bottom one Network Solutions Certificate Authority because I am a dumbass. So I downloaded that certificate to my local machine, and using the command,


keytool -keystore \lib\security\cacerts -import -alias network -file NetworkSolutionsCertificateAuthority.cert -trustcacerts


was able to get rid of the above error.


Naturally, this caused a different error to appear. This time it was an error saying

sun.security.validator.ValidatorException: PKIX path building failed:

sun.security.provider.certpath.SunCertPathB

uilderException: unable to find valid certification path to requested target


After digging around for days, I realized that the other 2 certificates in the hierarchy from the WSDL in the browser needed to be added as well. So I followed the same steps to download those certificates and keytool them into my cacerts file. Finally I was able to generate the java using Axis's WSDL2Java command.


But wait, there's more. Probably due to how my eclipse, tomcat, and environment variables are configured, when I tried to call one of the web services the jxapi offers, login, I was encountering the same exact piece of trash error "unable to find valid certification path to requested target."


WTF said I.


The issue here, was the related to what I mentioned way at the top of this beast of a post. There are 2 cacerts files. My Dos prompt used the one at /lib/security, while Eclipse/Tomcat, used the one located at /jdk/jre/lib/security.


Once both cacerts files were the exact same, everything started working fine.


Hopefully this helps someone. It was uncool having to figure all this crap out.


This is my first post, and I can't sort out all the font crap, so forgive the length and look of this blathering. I'll pare it down to essentials on future posts. Maybe.