Universal Package Tracking in ColdFusion
Join the DZone community and get the full member experience.
Join For FreeA while back, I was in need of a universal package tracking tool that is not specific to the carrier. Almost every carrier provides some kind of an API but it can be a pain to set up each one separately. Fortunately, I found a nifty tracking tool which is universal and can be leveraged through RSS. It works with UPS, FedEx, USPS, or DHL/AirBorne without having to specify which carrier you need. Instead, it determines the carrier from the tracking number.
You can check it out at http://isnoop.net/tracking/ and the some details can be found at http://isnoop.net/blog/?p=19.
While this might not be good commercial solution, it is still usable for personal or a small site. The code below shows how to leverage this with ColdFusion. The Ajax/JavaScript implementation relies on Prototype.js. You can see it in action at http://blog.tech-cats.net/examples/universalPackageTracking.cfm and download it from http://blog.tech-cats.net/examples/universalPackageTracking.txt
The code is well documented and should be easy to read/understand:
You can check it out at http://isnoop.net/tracking/ and the some details can be found at http://isnoop.net/blog/?p=19.
While this might not be good commercial solution, it is still usable for personal or a small site. The code below shows how to leverage this with ColdFusion. The Ajax/JavaScript implementation relies on Prototype.js. You can see it in action at http://blog.tech-cats.net/examples/universalPackageTracking.cfm and download it from http://blog.tech-cats.net/examples/universalPackageTracking.txt
The code is well documented and should be easy to read/understand:
<cfsetting enablecfoutputonly="yes"> <!--- Setup default parameters and constants ---> <!--- Is this call to the page from javascript (Ajax) ---> <cfparam name="url.isAjaxCall" default="false" /> <!--- The message to display while loading ---> <cfset loadingMessage = "Loading..." /> <!--- Default tracking number as a url variable (trackingNumber) ---> <cfparam name="url.trackingNumber" default="" /> <!--- Tracking page url: very nice free tracking for all carriers that you can call to get an rss feed generated based on your tracking number as in 'http://isnoop.net/tracking/index.php?t=85642012466&rss=1'. If you call it without setting the 'rss' variable as in: 'http://isnoop.net/tracking/index.php?t=85642012466' you can see a nice google map of where in route your package is. This service works for UPS, FedEx, USPS, or DHL/AirBorne without having to specify the carrier as it determins it from the tracking number. ---> <cfparam name="trackingPageUrl" default="http://isnoop.net/tracking/index.php" /> <!--- Function: parseRss Arguments: rssData string (The string of rss xml retrieved with cfhttp) debugMode boolean Return Value: An array of structures containing the parsed rss feed. Example: array[1] link - the link from the rss item title - the title from the rss feed description - the description from the rss feed Description: Parses the RSS feed passed in ---> <cffunction name="parseRss" returntype="array" output="true" hint="Parses the RSS feed passed in"> <cfargument name="rssData" type="string" required="true"> <cfargument name="debugMode" type="string" required="false"> <!--- Set default variables ---> <cfset var xmlData = ""> <cfset var result = arrayNew(1)> <cfset var x = ""> <cfset var items = ""> <cfset var xPath = ""> <cfset var node = ""> <cftry> <!--- Parse the data as xml ---> <cfset xmlData = xmlParse(arguments.rssData)> <!--- Create xpath search string based on the xml root name ---> <cfif xmlData.xmlRoot.xmlName is "rss"> <cfset xPath = "//item"> <cfelse> <cfset xPath = "//:item"> </cfif> <!--- Get all the xml nodes matching the xpath search string ---> <cfset items = xmlSearch(xmlData, xPath)> <!--- Loop through the found xml nodes and build an array of structures ---> <cfloop index="i" from="1" to="#arrayLen(items)#"> <cfset node = structNew()> <cfset node.link = items[i].link.xmlText> <cfset node.title = items[i].title.xmlText> <cfset node.description = items[i].description.xmlText> <cfset result[arrayLen(result) + 1] = duplicate(node)> </cfloop> <cfcatch> </cfcatch> </cftry> <cfreturn result> </cffunction> <cfoutput> <!--- If this is an ajax call, get the tracking results trackingPageUrl specified above ---> <cfif url.isAjaxCall and url.trackingNumber neq ''> <cfhttp method="get" url="#trackingPageUrl#" result="test" charset="windows-1252"> <!--- Set the 'rss' url variable ---> <cfhttpparam name="rss" type="url" value="1" /> <!--- Set the tracking url variable ---> <cfhttpparam name="t" type="url" value="#url.trackingNumber#" /> </cfhttp> <!--- Parse the rss feed from the contents returned by cfhttp ---> <cfset rssFeed = parseRss(test.filecontent) /> <cfif arraylen(rssFeed) gt 0> <div id="rssItem"> <span id="description">Tracking data for tracking number '<span id="trackingNumber">#url.trackingNumber#</span>'</span> </div> <br /> <!--- Loop through the contents of the rss feed and display them ---> <cfloop index="i" from="1" to="#arrayLen(rssFeed)#"> <div id="rssItem"> <span id="description">#rssFeed[i].description.replaceall("Package update on ", "")#</span> </div> </cfloop> <cfelse> <div id="rssItem"> <span id="description">No tracking data found for tracking number '<span id="trackingNumber">#url.trackingNumber#</span>'</span> </div> </cfif> <cfelse> <!--- This is not an ajax call, so display a form for the user to enter a tracking number ---> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script type="text/javascript" src="/js/prototype.js" mce_src="/js/prototype.js"></script> <style type="text/css"> span##trackingNumber { font-weight: 700; } div##statusContainer { position:absolute;left:0px;top:0px;width:100%;height:10px; } div##statusMessageContainer { position:absolute;background-color:##000000;color:white;width:70px;font-family:Arial, Helvetica, sans-serif;padding:2px;left:0px; } </style> </head> <body> Browser Bookmarklet: <a href="javascript:(function(){var url='http://#cgi.http_host##cgi.script_name#';searchString=prompt('Enter your tracking number:','');searchString=((searchString==null)?'':searchString.replace(/^(\s+)?(.*?)(\s+)?$/gi,'$2'));var params='?isAjaxCall=true&t=';if(searchString!=''){if(location.href.indexOf(url)==-1){var win=window.open(url+params+escape(searchString));}else{location.href=url+params+escape(searchString);}}})();"> Track Packages </a> <br /><br /> <form id="trackingForm" name="trackingForm" method="get" action="#cgi.script_name#" class="ajaxForm"> <input type="hidden" id="isAjaxCall" name="isAjaxCall" value="true" /> <input type="text" id="trackingNumber" name="trackingNumber" value="1Z04WF350314328154" /> <input type="submit" id="getTrackingResults" name="getTrackingResults" value="Track" /> </form> <br /> <!-- Results container that will be updated with the results of the request ---> <div id="resultsContainer" class="ajaxContent"></div> <br /> <!-- Status container that will be display durring processing ---> <div id="statusContainer" style="display: none;" class="ajaxStatus"> <div id="statusMessageContainer">Loading...</div> </div> <script language="javascript" type="text/javascript"> var trackingForm = Class.create(); trackingForm.prototype = { ajaxContainerElement: 'div', formID: '', ajaxUrl: '', resultsContainer: '', /* Function: initialize Description: Performs various intiliazion tasks for the form */ initialize: function() { var ajaxFormsList = $$('form.ajaxForm'); var ajaxContainersList = $$(this.ajaxContainerElement + '.ajaxContent'); if (ajaxFormsList.length > 0 && ajaxContainersList.length > 0) { this.formID = ajaxFormsList[0].id; this.ajaxUrl = $(this.formID).action; this.resultsContainer = ajaxContainersList[0].id; // Tie the submit event to the submitForm function $(this.formID).observe('submit', this.submitForm.bind(this)); // Reset the form $(this.formID).reset(); // Activate the first element on the form $(this.formID).findFirstElement().activate(); } }, /* Function: submitForm Description: Submits the form */ submitForm: function(event) { // Serialize the form parameters to pass them along as part of the form submission var params = $(this.formID).serialize(true); // Check if the tracking number is empty if (!params.trackingNumber.empty()) { // Disable the form $(this.formID).disable(); // Make an ajax request passing it the serialized form new Ajax.Updater( $(this.resultsContainer), this.ajaxUrl, { method: 'get', parameters: params, onFailure: this.reportError.bindAsEventListener(this), onSuccess: this.processResults.bindAsEventListener(this), evalScripts: true } ); } // Prevent the form from being submitted Event.stop(event); }, /* Function: processResults Description: Processes the server results */ processResults: function() { // Enable the form $(this.formID).enable(); // Reset the form $(this.formID).reset(); // Activate the first element on the form $(this.formID).findFirstElement().activate(); }, reportError: function(request){} }; Event.observe(window, 'load', function() { var ajaxStatusContainersList = $$('div.ajaxStatus'); var ajaxStatusContainer = ''; // Create an instance of the form object defined above trackingFormInstance = new trackingForm(); if (ajaxStatusContainersList.length > 0) { ajaxStatusContainer = $$('div.ajaxStatus')[0].id; Ajax.Responders.register({ onCreate: function() { $(ajaxStatusContainer).show(); }, onComplete: function() { $(ajaxStatusContainer).hide(); } }); } }); </script> </body> </html> </cfif> </cfoutput>
Leverage (statistics)
API
Download
Implementation
Published at DZone with permission of Boyan Kostadinov, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
Effective Java Collection Framework: Best Practices and Tips
-
Microservices With Apache Camel and Quarkus
-
Avoiding Pitfalls With Java Optional: Common Mistakes and How To Fix Them [Video]
-
Writing a Vector Database in a Week in Rust
Comments