Derek has concerns about aggregator support for HTTP 301 redirects and ETag headers. I’d like to add aggregator support for user IDs to the list. It’s the wild west in RSS and aggregators right now and people will be hopping around for a while. So we need to easily transfer user IDs from aggregator to aggregator. And we need to balance that against the ability to refer others to RSS feeds without piggy backing on existing user IDs.
Plus, I think that people will always want a safety net of anonymity. So it might be nice to reserve a standard block of IDs for that purpose - an aggregator could then be configured to randomly use an ID from that block for a given feed.
I still think that email marketing has a lot of life left in it. But maybe RSS is ready to take on more of the load than I had thought.
I love RSS as much as anyone else, but we don’t do anyone any favors when we refuse to take off the rose-colored sunglasses. Chris Pirillo throws some brickbats at an RSS doubter, but I happen to agree with the doubter on several points:
You can’t reliably measure exposure via RSS.
You can’t control how RSS is displayed.
RSS doesn’t build a user database.
RSS is difficult to customize - as a response driver - the way email is.
Tim Bray brought up the issue of RSS Subscriber Counting before, but the nay-sayers shut down the conversation before we had a good answer. The most valuable subscribers are the most likely to be sitting behind a proxy server and the most likely to be lost in the shuffle. Just how is RSS going to address that?
Maybe I’m dense. But I don’t see how anyone is going to build a RSS user database, segment the users and target the segments independently - remembering that a user may belong to multiple segments. I happen to believe in 1-to-1 marketing, how does RSS fit into that world?
Now, maybe spam spells the end of email marketing. But I think email is important enough that we’ll fix it before it dies. And that we’ll see RSS become one of the tools in marketing’s toolchest - supplementing email, not replacing it.
Just playing around is one of my favorite ways of becoming familiar with software. Let’s see how we can use the BeanShell to prototype Hibernate. I’m partial towards the BeanShell because it’s embedded in my Java Development Environment for Emacs. But if you’re so inclined, then Jython will probably do as well. Just in case there is a lurking configuration gotcha, here’s my current Java software configuration.
I must confess that I wasn’t planning on using the BeanShell. I was planning on adding a simple interpreter with java.io.StreamTokenizer to allow interactive manipulation of Keyword and KeySet objects. And then I realized that by setting the fork attribute of the java task to true separated my application from the console input. And setting it to false terminates the application with an java.lang.ExceptionInInitializerError. The BeanShell was my ticket out.
BeanShell support requires just a handfull of minor changes to our build file. First, the BSH property is added to reference the BeanShell jar and it is prepended to classpath.run to form classpath.bsh. Second, a new bsh target is added in parallel to the run target – note that we use class bsh.Console rather than bsh.Interpreter because we still lose access to console input because of the JVM fork. And Finally, the dist target was modified to include a bsh sub-directory.
Next, we’ll create a Scripted Object to simplify our interaction with hibernate. The Hibernate method returns an object that provides easy access to the most common functionality: open, save, find, delete and close.
Finally, two methods were added each of the KeySet and Keyword classes. The KeySet class gained an add and a remove method that simply provide access to the corresponding methods of the java.util.Set member variable. And the Keyword class gained methods for hashCode and equals – this insures that Keyword objects are equivalent when their String member variables are equivalent.
And now we’re ready to play with the BeanShell (starting with an empty database). By the way, if you’re anything like me, then the number one thing to remember is use print rather than println.
We can use the BeanShell to see that we cannot use Hibernate for immutable objects need to be careful when comparing objects from different sessions:
1.3b2 - by Pat Niemeyer (pat@pat.net)
bsh % source("bsh/Hibernate.bsh");
bsh % import hb.*;
bsh % hb = Hibernate();
bsh % tx = hb.transaction();
bsh % a = new Keyword("red");
bsh % s = new KeySet("colors");
bsh % s.add(a);
bsh % print(s);
{-1:colors|[-1:red]}
bsh % hb.save(s);
bsh % tx.commit();
// Error: // Uncaught Exception: Method Invocation tx.commit :
at Line: 1 : in file: <unknown file>
: tx .commit ( )
Target exception: net.sf.hibernate.TransientObjectException:
object references an unsaved transient instance
- save the transient instance before flushing
net.sf.hibernate.TransientObjectException:
object references an unsaved transient instance
- save the transient instance before flushing
at net.sf.hibernate.impl.SessionImpl.getEntityIdentifierIfNotUnsaved (SessionImpl.java:2357)
at net.sf.hibernate.type.EntityType.getIdentifier(EntityType.java:55)
at net.sf.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:33)
at net.sf.hibernate.collection.CollectionPersister.writeElement(CollectionPersister.java:458)
at net.sf.hibernate.collection.Set.writeTo(Set.java:226)
at net.sf.hibernate.collection.CollectionPersister.recreate(CollectionPersister.java:692)
at net.sf.hibernate.impl.ScheduledCollectionRecreate.execute(ScheduledCollectionRecreate.java:23)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2101)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2077)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2017)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at bsh.Reflect.invokeOnMethod(Unknown Source)
at bsh.Reflect.invokeObjectMethod(Unknown Source)
at bsh.Name.invokeMethod(Unknown Source)
at bsh.BSHMethodInvocation.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.BSHPrimaryExpression.eval(Unknown Source)
at bsh.Interpreter.run(Unknown Source)
at java.lang.Thread.run(Thread.java:554)
bsh % tx.rollback();
bsh % hb.close();
I was fortunate enough to ride out the entire blackout of ‘03 from the comfortable confines of home – Fairfield County, Connecticut. My girlfriend usually has an easy counter-commute home, but the lack of signals turned it into a slow slog. We had some peanut butter sandwiches for dinner with fresh strawberries for dessert. Then after reading by battery powered lantern for a bit we called it a night.
Our power came back around 4 or 5 am, but there are a lot of people in southwestern CT who are still without power. Looks like it’s going to be a lazy day.
One of the hardest tasks in developing new systems is knowing where to draw the line - include too much and you’ll never finish, include too little and all you have is a toy. So I think that Joi is being a bit harsh in his guess that there were people who were voicing concerns who had more vision. The problem lies in separating the true visionaries from the false prophets. SMTP and IPv4 have had a pretty good run over the past few decades - not too bad for what were essentially 0.x releases.
Now if Joi wants to throw some brickbats at those who deny that there is a problem or those who stand in the way of improvement while waiting for a perfect solution, then the line forms behind me.
It comes as a complete surprise, but Queer Eye for the Straight Guy has earned a spot on my weekly viewing schedule. The prospect of watching 5 gay guys (the Fab 5) make over a straight guy didn’t resonate with me at first. But I gave it a try based upon good reviews from friends and now I’m hooked.
Now, the initial visit to the bachelor digs with the requisite snide deconstruction of the wardrobe and decor has gotten old. But the show picks up once the Fab 5 start reconstructing - a product placement nirvana. And watching the big event with the Fab 5 in the peanut gallery is a hoot.
A new entry on my list of guilty pleasures. Of course, as a Tri-State resident, the real guilty pleasure is daydreaming about what they could do with me.
I was doing the usual obsessive compulsive review of my referrals when I came across fredshouse.net. Gene and I go waaay back, and I’m happy to welcome him to the blogroll (maybe this will get him off the snide at Technorati).
In other blogroll news, the BallBlog is joining the blog gang at FanBlogs. I think that we’re going to see more blogging confederations as individuals find themselves unable to write as frequently as they’d like.
Maybe it’s a function of the tools, but I’m surprised that I don’t see more confederations formed by a central blog linking to contributor blogs. It’s hard for an individual to maintain critical mass over multiple categories. But a group can easily maintain an on-topic critical mass while letting the individuals maintain a more eclectic style at home.
I choose to make the full content of Take the First Step is available in my RSS feeds. But if someone has made a conscious decision to have excerpts rather than the full post in their feed, then that’s fine by me. In fact, if their website is part of their brand, then that’s the right choice for them.
What Sean really needs is a NewsReader that acknowledges that we live in a world of Always drifting between On and Off. A reader that would let him mark articles to be downloaded and read at a later time. And eventually, a Reader with predictive capability that could pre-fetch articles for you.
Our series on Hibernate continues with the addition of a Hibernate collection. The collection is a basic building block in programming and storing Keyword objects inside a KeySet collection object gives us an easy way to query and display our persistent objects.
The first step in implementing our KeySet class is deciding whether there will be a one-to-many or a many-to-many relationship between KeySet and Keyword objects. A Keyword object may not be contained in multiple KeySet objects in a one-to-many relationship and it may be contained in multiple KeySet objects in a many-to-many relationship.
This example will use a many-to-many relationship. This requires a new table with two foreign keys tying KeySets and Keywords rows together – a one-to-many relationship would require a foreign key in the Keywords table that referenced the KeySets table. The KeySet.hbm.xml file follows (comments show the SQL used to create the respective tables). It is quite similar to the Keyword.hbm.xml file with the addition of the set tag.
We will skip the KeySet.java class as it is primarily boilerplate get/set methods and is quite similar to the Keyword.java class. However, please note that there are some changes to our Keyword implementation:
The parameter definition unsaved-value=”-1” has been added to Keyword.hbm.xml to explicitly declare an unsaved id value. And the static final int unsaved_value = -1 has been added to the Keyword java file and is used to set the initial value of the id member value. The two values need to match and should correspond to an invalid id value.
The default constructor and the setId function are now protected. Hibernate sets the id when an object is loaded or saved and everything else should leave it alone.
A toString() method has been added for easy output.
In addition, the build.xml file has been modified to add a DEBUG property that defines the value of the debug attribute of the javac task. The DEBUG property is set to true and Java source is now compiled with debug information.
Now let’s take a look at some code to load, query and create persistent objects. First, don’t forget to add the class to the configuration object. The error message “net.sf.hibernate.QueryException: unexpected token: as [from KeySet as ks …]” can be a bit perplexing until you’ve encountered it a few times.
tx = session.beginTransaction(); List existing = session.find( "from KeySet as ks where ks.name='colors'" );
If we find the KeySet we’re looking for, then we print it. Otherwise, we create a KeySet object, populate it with two Keyword objects and persist all three objects.
Now, start with a clean database and execute twice:
1
$ ant run
Buildfile: build.xml
init:
compile:
clean-run:
setup-run:
run:
[java] Create {0:colors|[1:blue, 0:red]}
BUILD SUCCESSFUL
Total time: 14 seconds
$ ant run
Buildfile: build.xml
init:
compile:
clean-run:
[delete] Deleting: /Projects/Learn/Hibernate/Simple/hibernate.log
setup-run:
run:
[java] Read {0:colors|[0:red, 1:blue]}
BUILD SUCCESSFUL
Total time: 13 seconds
Success, we’ve stopped adding persistent objects to the database with every execution. And we’ve stored and retrieved objects. You can download the source for this simple Hibernate collection. As a reminder, here is my hibernate software configuration.
Disclaimer: I don’t claim to be an expert on hibernate. Please send comments and corrections.