Amazon launched a new search engine today… a9.com, more from John Battelle.
All posts by ajohnson
J2EE Email Marketing Software
The company I’m working for is looking for an email marketing solution. Requirements:
- doesn’t cost an arm and a leg
- open, extensible
- J2EE based
- enjoyable to use
In short, if you know where I can find the JIRA of email marketing systems, I’d love to know about it. Feel free to comment (or email me directly).
Bouncy Castle 1.23 released…
The folks at Bouncy Castle released version 1.23 which includes a ton of fixes for the openpgp package. Read more about it here.
ASP.NET: Data-binding array of hashtables
Spent this morning in ASP.NET land working on a small modification in which I needed to data bind an array of hashtables to an <asp:repeater>. Looks like some other ASP.NETers had the same problem, but the ‘solutions’ they offered didn’t seem to solve the errors I was getting. First, in the code behind, I had something like this in the code behind:
public Repeater events = new Repeater();
private ArrayList aEvents = new ArrayList();
public void Page_Load(Object sender, EventArgs e) {
Hashtable event1 = new Hashtable();
event1.Add("name", "name of event 1");
event1.Add("date", "5/31/2004");
Hashtable event2 = new Hashtable();
event2.Add("name", "name of event 2");
event2.Add("date", "06/20/2004");
aEvents.Add(event1);
aEvents.Add(event2);
events.DataSource = aEvents;
events.DataBind();
}
and then a standard repeater tag in my ASP.NET code:
<asp:repeater id="events" runat="server">
<ItemTemplate>
Name:<%# DataBinder.Eval(Container.DataItem,"name") %>
Date:<%# DataBinder.Eval(Container.DataItem,"date") %>
</ItemTemplate>
</asp:repeater>
The first error I got was DataBinder.Eval: 'System.Collections.Hashtable' does not contain a property with the name name.
, which means that the DataBinder uses reflection to find a property called ‘name’ on the current object in the iteration. This is a problem because obviously a hashtable doesn’t have a public property for ‘name’, it only has an associate array of values. The workaround, although I don’t know why this works, is to wrap the keys in a brackets:
Name:<%# DataBinder.Eval(Container.DataItem,"[name]") %>
Date:<%# DataBinder.Eval(Container.DataItem,"[date]") %>
Using brackets lets you use an array of hashtables as a datasource. Since this works, it might be helpful to add it to the Data Binding Expression Syntax guide on MSDN.
JavaServer Faces notes from NEJUG meeting
Just got back from the April NEJUG meeting on JavaServer Faces, which didn’t go so smoothly. The projector lamp went out about 10 minutes into the presentation, which left David Geary with no access to his slides for about 1.5 hours. He gracefully answered questions instead of going through his presentation; following are excerpts of the questions & answers I found intriguing. Hopefully he’ll post his slides, although the OnJava.com newsletter mentioned that JSF is *the* hot topic for the next couple months so I’m sure there is going to be apt coverage elsewhere.
· David was one of the original developers of Tiles, which was highlighted in the Struts in Action book I’ve read. It didn’t originally float my boat, but I should go back and look into it a bit more. On Oreilly: Programming Jakarta Struts: Using Tiles, Part 1, Part 2, Part 3, Part 4.
· 1 sentence summary of JSF: It’s Struts++ with an event model and components.
· On the record Sun will say that JSF doesn’t replace Struts, off the record it does.
· Also off the record, David mentioned that JSF might be (or is) the most expensive JSR ever.
· Lots of people were curious about how closely tied JSF was to JSP. The short answer is that it’s not, David mentioned that you simply need to ‘… create a new renderer..’ for whatever platform you are targeting. He mentioned multiple times that JSF is platform independent and that you could output to XUL, Swing or Midlets. Which makes me wonder how hard it would be to write a JSF application that outputs to Flex or Laszlo. Swing & Midlets though? I could be wrong, but I think what it actually does it create *data* that these platforms can then use. I don’t think you can create an application in JSF and then write a J2ME renderer that creates a jar file that you can deploy to a phone. Tell me if I’m wrong on that though, because it would be remarkable otherwise.
· Couple questions about the similarities between Webforms & ASP.NET. Some differences I picked up:
a) the tags and UI components aren’t browser aware, they don’t target a specific browser platform, which is different from ASP.NET (which will output different HTML depending on which browser is requesting data).
b) by default form data is persisted to session scope (is this really true?) although I don’t see how this is an improvement over Struts (which has form persistence already if you use the Struts <html:form> tags)
· Question re: the complexity of JSF: easier or harder to learn than Struts? David replied that he thought that newbies to each would take longer to learn JSF. Struts users should have an easier time learning how to use it.
· Question re: migrating from Struts to JSF: Take a look at the document Craig McClanahan put together here, Struts-Faces integration library
· Question re: Tapestry & WebWork: Both were definitely looked at during the JSR process, turns out the Tapestry guy is local to Boston.
· JSF supports 2 types of events: action events (which are fired onclick of a button or a link) and change events (which are fired when the value of an input component changes). Both require a round trip to the server, change events require the user to click on a submit button OR the developer to write a JavaScript onchange event handler to then fire the form submission process. This is different than ASP.NET, where you can declare onchange events in your ASP.NET tags and the corresponding JavaScript is automatically generated for you. Whether this is good or bad depends on how much you like the generated code, but it definitely makes it easier for people who don’t know anything about JavaScript).
· Question re: debugging: is it easier than Struts? No.
· David mentioned a couple times that he thought that Tomcat sucked and that he really likes Resin. Note to self: check out Resin
· The WebSphereâ„¢ Boston Users Group will be doing a presentation entitled “WSAD, JSF, and More” on April 29th. More information here.
That’s it for now.
Update 04/15/2004: The presentation files are now available on the NEJUG site.
Upgrading from Tomcat 4.x to 5.0.19: java.lang.IllegalStateException
Seems like this new ‘feature’ of Tomcat 5 is buried in Google, bringing it to the top for anyone interested. If you port a servlet from Tomcat 4.x to Tomcat 5 and you use (pseudo) code like this:
public void doPost(HttpServletRequest req,HttpServletResponse res) {
// some sort of logic
if (something) {
forward("/somewhere", req, res);
} else {
// do this
}
// continue on with the page
}
public void forward(String url, HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
RequestDispatcher rd = req.getRequestDispatcher(url);
rd.forward(req, res);
}
you’ll find that the servlet will throw a java.lang.IllegalStateException
with the message: Cannot forward after response has been committed
. This condition is easily fixed by adding a ‘return’ statement after you call the forward method. So instead, you’d have this:
if (something) {
forward("/somewhere", req, res);
return;
} else {
// do this
}
// continue on with the page
I bet this one catches alot of people coming from a scripting background where it’s fine and dandy to do a response.redirect() (ASP) or a <cflocation> and then continue on as if nothing had happened.
Read it on jakarta.apache.org here.
NEJUG April Meeting: Java Server Faces
If you live in the Boston area, check out the NEJUG meeting @ the Sun office in Burlington this Thursday. David Geary will be giving an talk on Java Server Faces. Registration & further information here, you can read more about his book (Core JavaServer Faces) here.
I’ll be commuting from the city out to Burlington, ping me if you need a ride.
Wanted: Extracting summary from HTML text
As part of a project I’m working on I need to extract content from an HTML page, in some sense creating a short 200 character summary of the document. Google does a fantastic job of extracting text and presenting a summary of the document in their search listings, I’m wondering how they do that. Here’s the process I’m using right now:
a) Remove all of the HTML comments from the page (ie: <!– –>) because JavaScript is sometimes inside comments, which sometimes includes > and or < which causes (d) to fail
b) Remove everything above the <body> tag, because there isn’t anything valuable there anyway.
c) Remove all the <a href… > tags, because text links are usually navigation and are repeated across a site… they’re noise and I don’t want them. However, sometimes links are part of the summary of a document… removing a link in the first paragraph of a document can render the paragraph unreadable, or at least incomplete.
b) Remove all the HTML tags, the line breaks, the tabs, etc.. using a regular expression.
For the most part, the above 4 steps do the job, but in some cases not. I’ll go out on a ledge and say that most HTML documents contain text that is repeated throughout the site again and again (header text like Login Now! or footer text like copyright 2004, etc…). My problem is that I want to somehow locate the snippets that are repeated and not include them in the summaries I create… For example, on google do this search and then check out the second result:
Fenway Park. … Fenway Park opened on April 20, 1912, the same day as Detroit’s Tiger Stadium and before any of the other existing big league parks. …
That text is way about 1/4 of the way down in the document. How do they extract that?
Parameters: a) I don’t know anything about the documents that I’m analyzing, they could be valid XHTML or garbled HTML from 1996, b) it doesn’t have to be extremely fast, c) I’m using Java (if that matters) , d) I’ve tried using the org.apache.lucene.demo.html.HTMLParser class, which has a method getSummary(), but it doesn’t work for me (nothing is ever returned)
Any and all ideas would be appreciated!
PGP Encryption using Bouncy Castle
It can’t be that hard. So given a couple hours of hacking with the library, here’s a fully illustrated example that shows how to encrypt a file using the Bouncy Castle Cryptography API and PGP. First, giving credit where credit is due, the example comes mostly from the KeyBasedFileProcessor example that ships with the Bouncy Castle PGP libraries. You can find it in the /src/org/bouncycastle/openpgp/examples directory if you download the source. I’ve simply unpacked the example a little, providing some pretty pictures and explanation of what the various pieces are.
As in any example, you need to have downloaded a couple libraries; in this case you need to visit http://www.bouncycastle.org/latest_releases.html and download the bcprov-jdk14-122 and bcpg-jdk14-122 jar files. Add those to your project, as in this example, simply make sure to add them to the classpath when running the example from the command line.
Next, while you don’t need to have PGP installed, you do need to have a at least one public keyring file available on your system. I’m using PGP 6.5.8 on Windows which automatically saves my public keyring for me. You can find the location of the keyring file by Edit –> Options –> Files from within the PGP Keys window. You should see something like this:
Note the location of the Public Keyring File.
Second, you’ll need to generate a keypair (if you don’t already have one). I won’t go into the how or why (I assume you know the how and why) but you do need to make sure that you create what the Bouncy Castle folks call a ‘RSA key’ or ‘El Gamal key’ (source) rather than a DSA key. If you try to use a DSA keypair (which I’m assuming is synonomous with Diffie-Hellman/DSS?), that I ran into:
org.bouncycastle.openpgp.PGPException: Can't use DSA for encryption
, which again is explained by the link above.
Now that you downloaded the appropriate libraries, created an RSA keypair and located your public keyring file, we’re ready to start. Open up your favorite Java IDE (I’m using Eclipse) and start by importing the appropriate libraries:
import java.io.*;
import java.security.*;
import org.bouncycastle.bcpg.*;
import org.bouncycastle.jce.provider.*;
import org.bouncycastle.openpgp.*;
I took a shortcut above and didn’t specify exactly what classes I wanted to import for clarity, if you’re using Eclipse you can easily clean that up by selecting Source –> Organize Imports (or by downloading the source code at the end of this example). Next the class declaration and the standard public static void main etc.. The KeyBasedFileProcessor example on the BouncyCastle website lets you pass in the location of the public keyring and the file you want to encrypt, I’m hardcoding it in my code so that it’s crystal clear what everything is:
// the keyring that holds the public key we're encrypting with
String publicKeyFilePath = "C:\\pgp6.5.8\\pubring.pkr";
and then use the static addProvider() method of the java.security.Security class:
Security.addProvider(new BouncyCastleProvider());
Next I chose to create a temporary file to hold the message that I want to encrypt:
File outputfile = File.createTempFile("pgp", null);
FileWriter writer = new FileWriter(outputfile);
writer.write("the message I want to encrypt".toCharArray());
writer.close();
Read the public keyring file into a FileInputStream and then call the readPublicKey() method that was provided for us by the KeyBasedFileProcessor:
FileInputStream in = new FileInputStream(publicKeyFilePath);
PGPPublicKey key = readPublicKey(in);
At this point it’s important to note that the PGPPublicKeyRing class (at least in the version I was using) appears to have a bug where it only recognizes the first key in the keyring. If you use the getUserIds() method of the object returned you’ll only see one key:
for (java.util.Iterator iterator = key.getUserIDs(); iterator.hasNext();) {
System.out.println((String)iterator.next());
}
This could cause you problems if you have multiple keys in your keyring and if the first key is not an RSA or El Gamal key.
Finally, create an armored ASCII text file and call the encryptFile() method (again provided us by the KeyBasedFileProcessor example:
FileOutputStream out = new FileOutputStream(outputfile.getAbsolutePath() + ".asc");
// (file we want to encrypt, file to write encrypted text to, public key)
encryptFile(outputfile.getAbsolutePath(), out, key);
The rest of the example is almost verbatim from the KeyBaseFileProcessor example, I’ll paste the code here, but I didn’t do much to it:
out = new ArmoredOutputStream(out);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedDataGenerator.ZIP);
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(PGPEncryptedDataGenerator.CAST5, new SecureRandom(), "BC");
cPk.addMethod(encKey);
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes);
cPk.close();
out.close();
One last thing that I gleamed from their web-based forum was that one of the exceptions thrown by the above code is a PGPException, which itself doesn’t tell you much (in my case it was simply saying exception encrypting session key
. PGPException can be a wrapper for an underlying exception though, and you should use the getUnderlyingException() method to determine what the real cause of the problem is (which lead me to the Can't use DSA for encryption
message that I mentioned above).
You can download the source code and batch file for the example above here:
Updated 04/07/2004: David Hook wrote to let me know that there is a bug in the examples, I updated both the sample code above and the zip file that contains the full source code. Look at the beta versions for the updated examples.
re: Why Do Java Developers Like to Make Things So Hard?
James Turner, a committer on the Struts project and a Senior Editor at LinuxWorld Magazine, wrote an article for the magazine a couple days ago that caught the eye of a couple bloggers (Beattie, Colburn). There are a bunch of interesting comments on Russell’s blog in reference to his commens on the article. Notable among the comments:
… the difference between “Computer Science” and “Software Engineering” – the former being concerned with fundamental constructs and abstractions, the latter being concerned with putting them together into useful things — sort of like the distinction between Physics and Mechanical Engineering (or perhaps Civil Engineering), although much the way Computer Science is an abuse of the term Science, Software Engineering mistreats the term Engineering…. CS gives us things like Boyer-Moore search, Bloom filters, and LZ compression; SE gives us things like Apache and Google
— a link to an article that Joel Spolsky wrote back in 2001 (Don’t Let Architecture Astronauts Scare You)
— Carlos Perez chewed on the usuability of API’s for a bit (Even More Wisdom on Designing Usable APIs), which I found interesting because he talks about how Microsoft actually has done research into the usability of API’s (cognitive dimensions framework).
I think Russell misses the point; he brings up Bill Day using a PHP weblog solution as proof that Java is too hard. I use Moveable Type for my weblog, but that doesn’t mean I’d write a banking application in Perl or PHP. With that said, I completely agree with Mr. Turner’s assessment of the Bouncy Castle Crypto API. I tried to use it for the exact same thing that James did last week and I never did get it working. I bet we both would be using the Bouncy Castle API had they taken a couple hours to write a short and sweet introduction to the API.