The Long and Winding Method
- A Little Java Is Recommended
- Better Get a Bucket
- Building a Better Mousetrap
- Nearing the Solution of Zeno's Paradox
What a fantastical world we live in. Despite my bemoaned lack of a Jetson's-style flying car, I do have a lot of other neat stuff. None of it flies, unless I throw it, but these pieces of technology do have a certain charm. As I write these words, I'm seated comfortably in my recliner. A lap desk spans the arms of the chair, positioning my laptop computer at just the correct ergonomic typing height. As the spooky music from an X-Files rerun plays on the TV, an 11 Mbps wireless card contacts my home LAN and checks my email. If I had preferred, I could have chosen to listen to MP3s, the music piped into the living room from my office via 900 MHz wireless speakers. Everything I need to do can be accomplished in ridiculous repose with my behind cradled in burgundy leather.
The multifunction remote for the TV, DVD, digital cable, and stereo lies close at hand to my right. A spread-spectrum digital phone and my cell phone share space with the remote on the end table. Both phones have Caller ID displays so that I can ignore telemarketers. On my left, another table holds the all-important tall, cold one. Perched on the headrest of the recliner, my cat, Kali, stretches languorously, satisfied with a life of idle luxury.
By comparison, the work environment is a sweatshop. From every corner, the curses of frustrated developers rain down into my cube. At least that invective drowns out the soul-stealing hum of the fluorescent lighting and the incessant clicking of keyboards. My chair isn't too bad. I pilfered it from the office of one of InformIT's departed, but it isn't exactly a Barcalounger. And it's a far stretch from making up for the fact that I have to stare at a wall for eight hours a day. The windows are on the other side of the building. I won't even bring up the monolithic air duct that runs through the middle of my cube—Shafthenge, as I call it.
All right, none of this is exactly the fare you would find in Dante's Inferno, but as Einstein pointed out, everything is relative. I'm thinking of faking an injury, perhaps to a vertebra or metatarsal. I'd concoct a head injury, but they all think I have one already. I'd claim anything that could keep me at home to type away in peace from the comfort of my high-tech sanctum sanctorum.
A Little Java Is Recommended
Alas, that's enough wistful longing. There is some heavy digging to be done, and it's best that we get started. I promised some high-octane Java, and that's what I plan to deliver. We were going to find out the mysteries of the InformIT Recommends section of the MyInformIT page, as seen in the now-familiar Figure 1.
Figure 1 MyInformIT one more time.
We start our journey, as mentioned in the last installment, at the Java function informit.RecommendedBooks.getBucketResults(). Here again is what getBucketResults() looks like:
1 public void getBucketResults() 2 { 3 Recordset RS = null; 4 Recordset Count = null; 5 6 this.verifyClauses(); 7 8 if ( user_interests_exist || 9 user_certifications_exist || 10 user_job_titles_exist ) 11 { 12 // 13 // we know the user and they have a profile 14 // 15 16 if ( user_interests_exist && 17 user_certifications_exist && 18 user_job_titles_exist ) 19 { 20 setBucketResults( 1 ); 21 } 22 else 23 { 24 if ( user_interests_exist ^ 25 user_certifications_exist ^ 26 user_job_titles_exist ) 27 { 28 setBucketResults( 1 ); 29 } 30 else 31 { 32 setBucketResults( 0 ); 33 } 34 } 35 } 36 37 }
Did you ponder it, as I asked? No matter, you get to go on the ride anyway. Line 6 calls this.verifyClauses(), and we begin there. The class informit.RecommendedBooks is actually a subclass of informit.InformITRecommends. That class is a subclass of ProductBucket, which is a subclass of GenericBucket. GenericBucket is a subclass of java.lang.Object. As Beavis and Butt-head might say, "There is none higher." So we have a chain of inherited classes that can all share methods. The method this.verifyClauses() actually resides all the way up the chain in GenericBucket. Let's open the drapes and see what verifyClauses is up to.
1 protected void verifyClauses() 2 { 3 if ( getRelatedProductFromClause() != null ) 4 { 5 if ( getRelatedProductFromClause().equals("") ) 6 { 7 setRelatedProductFromClause(null); 8 } 9 } 10 else 11 { 12 setRelatedProductFromClause(null); 13 }
The first thing we want to do is check for a field from the database. You might remember from the last article that I discussed product_from_clause, a field in the users table. When you update your profile customization page, the product_from_clause field is appended to store the names of the auxiliary tables that were touched. If you added a job description and a certification description in your profile, the product_from_clause would store "user_job_titles,user_certifications" in the row keyed to your unique user_id. Lines 3–13 above check for the existence of data in that field. If the field is null or set to an empty string, a public variable called related_product_from_clause is set to null by calling the method setRelatedProductFromClause(null).
14 if ( getUserID() != null ) 15 { 16 if ( getUserID().equals("") ) 17 { 18 this.setUserID( null ); 19 user_profile_tables = null; 20 } 21 } 22 else 23 { 24 user_profile_tables = null; 25 } 26 //
Next, we check to see if your user_id was set in the ASP that called this method. Remember that we retrieve your user_id from the session_id found on the query string. Every session_id corresponds to a unique user_id in the database, and from that we can determine for whom to fetch MyInformIT data. If the user_id is null or empty, we set it to null, along with another variable, user_profile_tables.
27 if (getRelatedProductFromClause() != null) 28 { 29 state_info_exists = true; 30 } 31 else 32 { 33 state_info_exists = false; 34 }
We set a flag, state_info_exists, to true if data was found in your product_from_clause. It's set to false if that database field was empty.
35 if ( user_profile_tables == null ) 36 { 37 user_interests_exist = false; 38 user_certifications_exist = false; 39 user_job_titles_exist = false; 40 }
We perform the same check in lines 35–40 above. If the variable user_profile_tables is not null, however, we can pull from it the tables for which you have associated data. user_profile_tables is set to hold the same comma-separated list as the product_from_clause variable, if that data exists.
41 else 42 { 43 user_profile_tables = user_profile_tables.trim(); 44 45 StringTokenizer st = 46 new StringTokenizer( user_profile_tables, 47 ",", 48 false ); 49 String current_token; 50 51 while (st.hasMoreTokens()) 52 { 53 current_token = st.nextToken(); 54 55 if ( current_token != null ) 56 { 57 if ( current_token.equalsIgnoreCase 58 ( "user_interests" ) ) 59 { 60 user_interests_exist = true; 61 } 62 63 if ( current_token.equalsIgnoreCase 64 ( "user_certifications" ) ) 65 { 66 user_certifications_exist = true; 67 } 68 69 if ( current_token.equalsIgnoreCase 70 ( "user_job_titles" ) ) 71 { 72 user_job_titles_exist = true; 73 } 74 75 76 } 77 78 current_token = null;
We use the Java StringTokenizer function on lines 45 and 46 to split the user_profile_tables string into its component parts, breaking on the commas. We then loop through the tokens to match our possible tables: user_interests, user_certifications, and user_job_titles. A flag is set to true for each possibility if a correlation is discovered. This particular programmer sets his temporary placeholder variable, current_token, to null when the loop is complete. Isn't he a tidy sort?
79 } 80 81 st = null; 82 83 84 }
He cleans up the StringTokenizer variable, too. Boy, he is fastidious! With our flags set for each auxiliary table where data exists, we exit verifyClauses() and return to getBucketResults().