Tuesday, December 18, 2007
JNI library testing on OSX 10.5
Refactoring a bunch of the JNI H-ITT code that I was working on last month caused me grief when I was nailed with the presence of UnsatisfiedLinkError during my maven build. My Mac prototype code was very simplistic and I had all the libraries (and Java test driver) in the same directory and it worked flawlessly. Sheesh, LD_LIBRARY_PATH in OSX 10.5 is not the right env variable, should be DYLD_LIBRARY_PATH. Once that was added to my pom I was good to go, tests passed as expected.
Thursday, December 13, 2007
Madison Summit Oxfords, second pair
Three years ago I wrote about a horrible experience with junk shoes from Wal-Mart . Tonight I bought my second pair of Timberland Madison Summit Oxfords. I love these shoes and forwarded my thoughts to Timberland:
To Whom it May Concern,
I just wanted to write a quick note and thank you for such fantastic shoes. Two years ago I was looking for a new pair of shoes that I could use for work (business-casual), for school (walking around college campus), for home (playing sports with my kids, shoveling the walk, and wearing around the house) and for anything else. I was talking with a fellow in my church congregation and he suggested Timberland. I headed over to a local sporting good store and the sales guy immediately showed me your Madison Summit Oxford.
I purchased that pair of shoes 23.5 months ago and they has served me very, very well. I have worn them exclusively, for every activity. The best part about this shoe was how well it "restored" when I regularly applied my leather-weather cream.
Tonight I purchased my new pair, the exact same size and model for $30 cheaper than two years ago. I commend you on a fine product and its outstanding endurance. I appreciate your company's values and commitment to the environment. I hope this next pair will last me another two years and that I can continue on with my Madison Summit Oxford addiction in the foreseeable future (2010, 2012, 2014...).
To Whom it May Concern,
I just wanted to write a quick note and thank you for such fantastic shoes. Two years ago I was looking for a new pair of shoes that I could use for work (business-casual), for school (walking around college campus), for home (playing sports with my kids, shoveling the walk, and wearing around the house) and for anything else. I was talking with a fellow in my church congregation and he suggested Timberland. I headed over to a local sporting good store and the sales guy immediately showed me your Madison Summit Oxford.
I purchased that pair of shoes 23.5 months ago and they has served me very, very well. I have worn them exclusively, for every activity. The best part about this shoe was how well it "restored" when I regularly applied my leather-weather cream.
Tonight I purchased my new pair, the exact same size and model for $30 cheaper than two years ago. I commend you on a fine product and its outstanding endurance. I appreciate your company's values and commitment to the environment. I hope this next pair will last me another two years and that I can continue on with my Madison Summit Oxford addiction in the foreseeable future (2010, 2012, 2014...).
Wednesday, December 12, 2007
TextMate: Subversion Annotate command
I really like vc-annotate in emacs. Considering the other very easy command I created earlier, thought I'd give this one a shot too (since it's not in the default Subversion bundle). Again, extremely simple and minutes to complete. Here's the command (edited from the Info command):
And here's the Ruby formatter:
require_cmd "${TM_SVN:=svn}"
: ${TM_RUBY:=ruby}
FORMAT_INFO="${TM_BUNDLE_SUPPORT}/format_annotate.rb"
"$TM_SVN" annotate "$TM_FILEPATH" |"$TM_RUBY" -- "$FORMAT_INFO"
And here's the Ruby formatter:
require ENV['TM_BUNDLE_SUPPORT']+'/svn_helper.rb'
include SVNHelper
puts html_head(:window_title => "Info", :page_title => "SVN Annotation", :sub_title => 'Subversion')
puts '<div class="subversion">'
STDOUT.flush
@colors = ['BlanchedAlmond',
'BlueViolet',
'Brown',
'BurlyWood',
'CadetBlue',
'Chartreuse',
'Chocolate',
'Coral',
'CornflowerBlue',
'Crimson',
'Cyan',
'DarkBlue',
'DarkCyan',
'DarkGoldenRod',
'DarkGray',
'DarkGreen',
'DarkKhaki',
'DarkMagenta',
'DarkOliveGreen',
'Darkorange',
'DarkOrchid',
'DarkRed',
'DarkSalmon',
'DarkSeaGreen'] #see http://www.w3schools.com/html/html_colornames.asp for more pretty colors
@color_hash = Hash.new
@color_ind_size = @colors.size() -1
def color_for_rev(rev)
color = @color_hash[rev]
unless (color)
color_index = rev % @color_ind_size
color = @colors[color_index]
@color_hash[rev] = color
end
color
end
$stdin.each_line do |line|
rev = line.strip.split(" ").first.to_i
color = color_for_rev(rev)
colored = "<div style='color:#{color}'>#{htmlize(line.strip)}"
puts(colored)
end
puts("</div>")
html_footer()
TextMate command db query prompt
I decided to give TextMate another whirl last night. I thought since I gave NetBeans 6 some time recently I'd see how efficient a couple of days with TextMate would be (compared with my life-blood emacs). I was pleasantly surprised at its extendability, speed and myriad of bundle choices. While perusing the SQL bundle I noticed I couldn't see of a way of directly typing in a query. I really like sql-mysql in emacs, so I was hoping I could do something similar--the workaround being typing a query into a buffer, selecting it, then invoking the command to send it. After poking around in the TextMate manual I was shocked at how easy it appeared to be to add custom commands. In less than a minute I had this (edited straight from the manual example of showing a dialog for input):
If I can just get over my remaining habits (screen splitting, hippie-expand, and more), I may end up paying for this editor. Too bad it's not OSS :(
res=$(CocoaDialog inputbox --title "Send query" \
--informative-text "Enter query text:" \
--button1 "Submit" --button2 "Cancel")
[[ $(head -n1 <<<"$res") == "2" ]] && exit_discard res=$(tail -n1 <<<"$res") db_browser.rb --query="$(tr '\n' ' ' <<< "$res")"
If I can just get over my remaining habits (screen splitting, hippie-expand, and more), I may end up paying for this editor. Too bad it's not OSS :(
Wednesday, November 21, 2007
Rxtx to MINA H-ITT Flash integration out of the park
That's a lame title, but it advertises all of the relevant (okay, short of Java's role, which is inherent since Apache MINA is written in Java) technologies in my latest project at work. We'll be using a Flash based application for our next training platform. One of the goals of the platform is to integrate an audience response system with the training. We specifically chose H-ITT as our provider because the offer a simple SDK (cross-platform translation library) and they appeared to have the most developed system and provide solid support.
Today I finished a proof of concept and made it available to them, here are the relevant sections of my email (heading home soon, this saves me time from repeating myself):
--begin email chunk--
I wanted to let you know that I have successfully completed a workable Windows H-ITT-Java-Flash prototype. I have some of the code operational in OSX but haven't pursued it in light of our goal of a single Windows deliverable (with embedded JRE) that _doesn't_ require an installation routine. I've used Java as the communication layer, natively interfacing through your SDK, and created a rudimentary TCP protocol for communication with the Flash application. I've heavily relied on the open-source Apache MINA project in conjunction with the Rxtx libraries (which will be included in a later stable release of MINA), Simple-Log and Launch4j.
The prototype simply exhibits the ability to auto-detect the transceiver's serial port (baud can be manually configured via a properties file, defaults at 19200), sets up the appropriate serial connection, and then forwards the responses to the Flash app. Java logging is written to disk unless executed from a read-only medium. The Flash prototype provides an "Acquire" button that kicks off the auto-detect, a log console (scrolling is there, but not so visible, I'm not a Flash guru), and also virtual buttons related to the remote. Thus, when configuration is successfully complete, pressing the buttons on the remote invokes the related event in the Flash app to show which button was pressed. The whole setup serves as a basic proof-of-concept for what we're pursuing with our next-gen training platform.
--end email chunk--
Thanksgiving is tomorrow, I'm feeling grateful: So I've already plugged H-ITT in the beginning of the post, but I really gotta say they've been great to work with and very prompt in answering questions. Next plug goes to the MINA team. MINA intuitively and simply (relatively, I thought the docs and examples were sufficient) provided a great framework for custom socket communication with Flash. It's elegantly architected (IMHO) and easily integrated with what I had envisioned for the Java communication layer. Props to Mike Heath for recommending MINA and assisting my approach. Simple-log and Launch4j simplified logging and customizing a single Windows .exe file. Lastly, Rxtx provided the crux of the serial-communication and I applaud the development team in their cross-platform approach and deliverables. Finally, my thanks to Ross Asay for the JNI help, since I was intending a cross-platform delivery to correspond with H-ITT's libraries this proved to be a good challenge and learning experience.
Today I finished a proof of concept and made it available to them, here are the relevant sections of my email (heading home soon, this saves me time from repeating myself):
--begin email chunk--
I wanted to let you know that I have successfully completed a workable Windows H-ITT-Java-Flash prototype. I have some of the code operational in OSX but haven't pursued it in light of our goal of a single Windows deliverable (with embedded JRE) that _doesn't_ require an installation routine. I've used Java as the communication layer, natively interfacing through your SDK, and created a rudimentary TCP protocol for communication with the Flash application. I've heavily relied on the open-source Apache MINA project in conjunction with the Rxtx libraries (which will be included in a later stable release of MINA), Simple-Log and Launch4j.
The prototype simply exhibits the ability to auto-detect the transceiver's serial port (baud can be manually configured via a properties file, defaults at 19200), sets up the appropriate serial connection, and then forwards the responses to the Flash app. Java logging is written to disk unless executed from a read-only medium. The Flash prototype provides an "Acquire" button that kicks off the auto-detect, a log console (scrolling is there, but not so visible, I'm not a Flash guru), and also virtual buttons related to the remote. Thus, when configuration is successfully complete, pressing the buttons on the remote invokes the related event in the Flash app to show which button was pressed. The whole setup serves as a basic proof-of-concept for what we're pursuing with our next-gen training platform.
--end email chunk--
Thanksgiving is tomorrow, I'm feeling grateful: So I've already plugged H-ITT in the beginning of the post, but I really gotta say they've been great to work with and very prompt in answering questions. Next plug goes to the MINA team. MINA intuitively and simply (relatively, I thought the docs and examples were sufficient) provided a great framework for custom socket communication with Flash. It's elegantly architected (IMHO) and easily integrated with what I had envisioned for the Java communication layer. Props to Mike Heath for recommending MINA and assisting my approach. Simple-log and Launch4j simplified logging and customizing a single Windows .exe file. Lastly, Rxtx provided the crux of the serial-communication and I applaud the development team in their cross-platform approach and deliverables. Finally, my thanks to Ross Asay for the JNI help, since I was intending a cross-platform delivery to correspond with H-ITT's libraries this proved to be a good challenge and learning experience.
Wednesday, September 12, 2007
Failed to get IPC connection
This convenient message showed up tonight on a Windows 2003 Server VM under VMWare server. Restarting the service, no go. Restarting the VM, no go (same message). Remove devices and change the VM settings, no go. Restarting host (Suse), no go.
A bit of looking around didn't help much, but someone mentioned a permissions issue. Here's the log entry:
Going out to the directory of the VM, and executing a "chown root:root -R ." did the job. Restarting the VM after that brought it up nice and happy. So the question remains as to what caused this to occur.
A bit of looking around didn't help much, but someone mentioned a permissions issue. Here's the log entry:
Sep 12 18:13:56: vmx| CnxAcceptConnection: Could not receive fd on 187: invalid control message
Sep 12 18:13:56: vmx| Failed to get IPC connection
Going out to the directory of the VM, and executing a "chown root:root -R ." did the job. Restarting the VM after that brought it up nice and happy. So the question remains as to what caused this to occur.
Wednesday, August 15, 2007
Why I love Apache's Ldap Studio
I've gotta modify some attributes on people in our ActiveDirectory. The fun Microsoft way to do this is to download ADAM-adsi management console plugin, and then go from there. It's pretty basic and is usual MS ugliness. On the other hand, Apache Ldap Studio provides a much better user experience. Being built on top of Eclipse enables a slick interface and a very intuitive way of dealing with your directory (browsing, searching, editing). Kudos to the guys that wrote it, I can now enjoy mucking with AD from my Mac with ease and finesse.
Thursday, August 09, 2007
Remote files in Emacs
Today I decided I was sick of always SSHing everywhere only to open up a couple of files for editing and then saving them. It doesn't make sense to copy my .emacs everywhere either. I discovered Tramp, and it just makes me all the more happy with my Emacs zealotry. Even better, my current snapshot already includes it.
Works great with dired too:
/ssh:hoser@somebox:/whateverdirectory
Works great with dired too:
/ssh:hoser@somebox:/whateverdirectory
Wednesday, August 01, 2007
installing the latest nginx on OS X
I've read a lot about nginx lately and wanted to test its performance for our up-and-coming Ruby on Rails CRM application. It looked very easy to setup and easily configurable (especially with this). My first attempt was installing it through MacPorts, but that didn't fly, as I received the unpleasant "dyld: Library not loaded: /usr/local/lib/libpcre.0.dylib". Turns out I had the same problem when trying to execute after building straight from source (which happened to be a newer version).
So with MacPorts I installed pcre 7.2_0, deactivated 7.0_0, created the symlink as "sudo ln -s /opt/local/lib/libpcre.0.dylib /usr/local/lib/" and was then able to start up nginx from the source build. Unfortunately the generated configuration file I am using expected a user and group for "nginx". A quick work around for that was to just reference myself instead. Here's what I ended up with (awaiting tweaks and optimizations):
So with MacPorts I installed pcre 7.2_0, deactivated 7.0_0, created the symlink as "sudo ln -s /opt/local/lib/libpcre.0.dylib /usr/local/lib/" and was then able to start up nginx from the source build. Unfortunately the generated configuration file I am using expected a user and group for "nginx". A quick work around for that was to just reference myself instead. Here's what I ended up with (awaiting tweaks and optimizations):
#user and group to run as
user russ russ;
# number of nginx workers
worker_processes 2;
# pid of nginx master process
pid logs/nginx.pid;
# Number of worker connections. 1024 is a good default
events {
worker_connections 1024;
}
# start the http module where we config http access.
http {
# pull in mime-types. You can break out your config
# into as many include's as you want to make it cleaner
include conf/mime.types;
# set a default type for the rare situation that
# nothing matches from the mimie-type include
default_type application/octet-stream;
# configure log format
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "http_x_forwarded_for"';
# main access log
access_log logs/access.log main;
# main error log
error_log logs/error.log debug;
#error_log logs/error.log debug_http;
# no sendfile on OSX
sendfile on;
# These are good default values.
tcp_nopush on;
tcp_nodelay off;
# output compression saves bandwidth
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml
application/xml+rss text/javascript;
# this is where you define your mongrel clusters.
# you need one of these blocks for each cluster
# and each one needs its own name to refer to it later.
upstream vscrm {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
# the server directive is nginx's virtual host directive.
server {
# port to listen on. Can also be set to an IP:PORT
listen 80;
# sets the domain[s] that this vhost server requests for
server_name vscrm;
# doc root
root /home/russ/forge/svn/vscrm/trunk/public;
# vhost specific access log
access_log logs/vscrm.access.log main;
#Set the max size for file uploads to 50Mb
client_max_body_size 50M;
# this rewrites all the requests to the maintenance.html
# page if it exists in the doc root. This is for capistrano's
# disable web task
if (-f $document_root/maintenance.html){
rewrite ^(.*)$ /maintenance.html last;
break;
}
if ($host ~* "www") {
rewrite ^(.*)$ http://vscrm$1 redirect;
break;
}
location / {
# needed to forward user's IP address to rails
proxy_set_header X-Real-IP $remote_addr;
# needed for HTTPS
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect false;
proxy_max_temp_file_size 0;
# check for index.html for directory index
# if its there on the filesystem then rewite
# the url to add /index.html to the end of it
# and then break to send it to the next config rules.
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
# this is the meat of the rails page caching config
# it adds .html to the end of the url and then checks
# the filesystem for that file. If it exists, then we
# rewite the url to have explicit .html on the end
# and then send it on its way to the next config rule.
# if there is no file on the fs then it sets all the
# necessary headers and proxies to our upstream mongrels
if (-f $request_filename.html) {
rewrite (.*) $1.html break;
}
if (!-f $request_filename) {
proxy_pass http://vscrm;
break;
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
Tuesday, July 31, 2007
sanitizing Rails input parameters
I really like how Tapestry automagically escapes HTML input when posted from a form. In fact, it was just great never having to worry about that when coding. I'd like to have the same functionality in Rails especially after reading about Rails XSS vulnerabilities and work-arounds. Since the webapp I'm writing has no requirements for allowing formatted user input, I just need something simple to clean/sanitize all the params. Here's the latest:
This is then invoked by a before_filter. Seems to do the job, is there a better/cleaner/faster way of doing this? Let me know how it could be improved...
#escapes all HTML from the given hash's values (recursively applied as needed)
def sanitize(hash)
dirty_hash = hash
dirty_hash.keys.each do |key|
value = dirty_hash[key]
if(value.kind_of?Hash)
dirty_hash[key] = sanitize(value)
else
if (value && value.kind_of?(String))
dirty_hash[key] = CGI.escapeHTML(value)
end
end
end
hash = dirty_hash
end
This is then invoked by a before_filter. Seems to do the job, is there a better/cleaner/faster way of doing this? Let me know how it could be improved...
Wednesday, July 11, 2007
Ruby: constant time for include?
Sure would be nice if the Ruby docs (including this book) would provide more details to the implementation of the Set class. According to this, Set implements its backing collection with a Hash, which would essentially mean that it's synonymous (to some degree) with Java's HashSet. Thus providing a constant time lookup when Set#include? is invoked. Just for grins I benchmarked this in irb with a million Fixnums and was pleased with the 15 microsecond lookups. I looked at the source of both and found a fair amount of similarity.
Friday, June 22, 2007
Sorting serialized objects from a YAML file, Ruby vs Java
I recently had a large dataset that I needed to sort, basically a bunch of objects with 9 string attributes. I dumped them to a YAML file so I could benchmark various aspects of sorting (Class#to_yaml really rocks, really). As it turns out Enumerable#sort_by was the more efficient way to go rather than Enumerable#sort (check it). The dataset contained 5429 unique objects, here's the benchmarking I did in irb:
Noticeable difference between the two methods, and quite pleasing to see how fast sort_by performed (Apple MBP 2.33GHZ 2GB RAM Ruby 1.85). Then the thought occurred to me, since I have this in a YAML file, I could write something really quick in Java and see how fast the sort would be by dumping it into a TreeSet.
So I set off to find out how I could marshal the data into POJOs from the YAML file. JYaml and JvYaml are the only (insofar as I looked) open source Java YAML libraries. Both seem half-baked in their own right, likely containing just the functionality the respective author needed and not much more (at least that's how it appeared). I ended up using JvYaml and had to search-replace the yaml entry identifier("tag:yaml.org,2002:map") so that JvYaml would create HashMap instances for me instead of its completely worthless PrivateType class.
From there I iterated through the maps to create the POJOs and shoved them into a HashSet. Once that was completed I created the comparator for my POJO, passed it into the TreeSet constructor and then timed an addAll giving it the entire HashSet:
#1: 55ms
#2: 28ms
#3: 27ms (pretty much constant thereafter)
Interesting results eh? The dataset I used was from a randomized generator and now that I have these initial numbers ( Ruby appears to have won this round), I want to test a larger set. And to be really fair I should do more research on benchmarking best practices (in addition to still needing to take my stats class).
>> bm do |x|
?> x.report("all"){results.sort{|a,b|a.account_name <=> b.account_name}}
>> end
user system total real
all 0.070000 0.000000 0.070000 ( 0.073835)
>> bm do |x|
?> x.report("all"){results.sort_by{|a|a.account_name}}
>> end
user system total real
all 0.020000 0.000000 0.020000 ( 0.020745)
Noticeable difference between the two methods, and quite pleasing to see how fast sort_by performed (Apple MBP 2.33GHZ 2GB RAM Ruby 1.85). Then the thought occurred to me, since I have this in a YAML file, I could write something really quick in Java and see how fast the sort would be by dumping it into a TreeSet.
So I set off to find out how I could marshal the data into POJOs from the YAML file. JYaml and JvYaml are the only (insofar as I looked) open source Java YAML libraries. Both seem half-baked in their own right, likely containing just the functionality the respective author needed and not much more (at least that's how it appeared). I ended up using JvYaml and had to search-replace the yaml entry identifier("tag:yaml.org,2002:map") so that JvYaml would create HashMap instances for me instead of its completely worthless PrivateType class.
From there I iterated through the maps to create the POJOs and shoved them into a HashSet. Once that was completed I created the comparator for my POJO, passed it into the TreeSet constructor and then timed an addAll giving it the entire HashSet:
#1: 55ms
#2: 28ms
#3: 27ms (pretty much constant thereafter)
Interesting results eh? The dataset I used was from a randomized generator and now that I have these initial numbers ( Ruby appears to have won this round), I want to test a larger set. And to be really fair I should do more research on benchmarking best practices (in addition to still needing to take my stats class).
Tuesday, April 17, 2007
X11 tunneling via SSH in OSX
-X isn't enough for the ssh args in OSX according to this post. So, "ssh -XY hoser@remotebox" worked just great when remoting in to a Suse server and firing executing fvwm.
Thursday, April 12, 2007
1024 vs 2048 RSA encryption/decryption fun in Ruby
Using Tobias's handy openssl wrapper I decided to run a couple timing tests to see how well Ruby's openssl implementation performed in encrypting/decrypting a set of 1000 identical messages, with 1024 bit and 2048 bit keys. Nothing scientific about this, just three runs of the script on my MacBook Pro (2.33 GHZ, 1G RAM).
Encrypted text: "This is a much longer message since than what I intend to encrypt"
Encryption results, avg time
1024: 0.000300691s
2048: 0.001010027s
Decryption results, avg time
1024: 0.005472064s
2048: 0.035524023s
Pick your poison.
Encrypted text: "This is a much longer message since than what I intend to encrypt"
Encryption results, avg time
1024: 0.000300691s
2048: 0.001010027s
Decryption results, avg time
1024: 0.005472064s
2048: 0.035524023s
Pick your poison.
Monday, April 02, 2007
One last hitch
According to this, friendly errors such as
prohibit the following default generated objects from correctly mapping when invoking the NetSuite searches:
Each of which contain an entity named 'class', and while soap4r intelligently generates an attribute 'v_class', it also erroneously generates accessor methods that override Object.class. Big woops. Extremely easy fix just by renaming those methods.
/opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:520:in `class_schema_variable': undefined method `class_variables' for nil:NilClass (NoMethodError)
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:353:in `schema_ns_definition'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/mapping.rb:380:in `schema_definition_classdef'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/registry.rb:198:in `schema_definition_from_class'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:73:in `any2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:37:in `obj2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:127:in `stubobj2soap'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:114:in `each'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/mapping/literalregistry.rb:114:in `stubobj2soap'
... 15 levels...
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/rpc/proxy.rb:126:in `call'
from /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/lib/soap/rpc/driver.rb:179:in `call'
from (eval):6:in `search'
prohibit the following default generated objects from correctly mapping when invoking the NetSuite searches:
- OpportunitySearchBasic
- EmployeeSearchBasic
- PartnerSearchBasic
- ItemSearchBasic
- TimeBillSearchBasic
Each of which contain an entity named 'class', and while soap4r intelligently generates an attribute 'v_class', it also erroneously generates accessor methods that override Object.class. Big woops. Extremely easy fix just by renaming those methods.
Wednesday, March 28, 2007
NetSuite and Ruby, the final chapter
NetSuite requires a maintainable session for subsequent requests after the initial login by way of several cookies they return upon successful authentication. The standard Net::HTTP library requires mucking with headers by hand in order to perpetuate cookie information. We were easily able to override SOAP::NetHttpClient::Response and SOAP::HTTPStreamHandler in the soap4r gem in order to provide the functionality for maintaining the NetSuite session.
However, NaHi's http-access2 library already provides cookie management (even persistence if needed). After installing visnu's gem it's simply a matter of turning off the SSLConfig#verify_mode and everything works flawlessly. The final test code:
However, NaHi's http-access2 library already provides cookie management (even persistence if needed). After installing visnu's gem it's simply a matter of turning off the SSLConfig#verify_mode and everything works flawlessly. The final test code:
require 'rubygems'Everything said and done, this has been a good learning experience. But more than anything it has exposed one of the Ruby community's greatest weaknesses: documentation. I've known this since the beginning of my Ruby days (2004) and have grown accustomed to reading code. Nevertheless, that takes time, and usually more time than scanning decently-documented APIs. The other side of this story is that I understand the Japanese/English language barrier which may intimidate or otherwise prevent library maintainers from providing more documentation. In the end, Ruby is a community-driven language, which is not sponsored by massive corporate dollars (cough, Java, cough, .Net) and its beginnings have solid Japanese roots. Here's to hoping that documentation improves as more libraries become available and the language matures. In the mean time, thank goodness for Google, mailing lists, blogs and IRC. I believe that documentation practices exhibited by 37Signals and the Rails community are the guiding example, they're not perfect, but the situation continues to progress.
require_gem 'soap4r'
require 'defaultDriver' #generated by soap4r
require 'pp'
driver = NetSuitePortType.new
driver.wiredump_dev = STDOUT
driver.proxy.streamhandler.client.ssl_config.verify_mode = nil
passport = Passport.new
passport.email = '123123123@123123123.com'
passport.password = '123123123'
passport.account ="123123"
passport.role = RecordRef.new
passport.role.xmlattr_internalId = '123123123'
driver.login(LoginRequest.new(passport))
record = RecordRef.new()
record.xmlattr_internalId = '123123123'
record.xmlattr_type = RecordType::Customer
pp driver.get(GetRequest.new(record))
soap4r and NetSuite revisited
In the last post I mentioned that the generated file (default.rb) contained redundant object definitions. I also ended with the concern about the RecordRef element not appearing to be correct. That led me to look at the generator and as it turns out I was invoking the wrong one. Funny thing, the soap4r gem ships with wsdl2ruby.rb and places them in two different locations. The first (in OSX) was in /opt/local/bin where the second was in /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/bin/. Yesterday we explictly invoked the one in the gem, disregarding the the executable wrapper in /opt/local/bin. That was the mistake, as the results can be easily reproduced with executing
Using the correct wsdl2ruby the following test works without any modifications to the generated code:
ruby /opt/local/lib/ruby/gems/1.8/gems/soap4r-1.5.5.20061022/bin/wsdl2ruby.rb --wsdl https://webservices.netsuite.com/wsdl/v2_5_0/netsuite.wsdl --type clientThe problem being that the wrapper adds the necessary "requires" for referencing the gem's code (correct results) and not the standard (incorrect results).
Using the correct wsdl2ruby the following test works without any modifications to the generated code:
require 'rubygems'
require_gem 'soap4r'
require 'defaultDriver'
driver = NetSuitePortType.new
driver.wiredump_dev = STDOUT
passport = Passport.new
passport.email = 'test'
passport.password = 'test'
passport.account ="test"
role = RecordRef.new
role.xmlattr_internalId = '123123123'
passport.role = role
response = driver.login(LoginRequest.new(passport))
pp "successful login: #{response.sessionResponse.status.xmlattr_isSuccess}"
Tuesday, March 27, 2007
adventures in soap4r and NetSuites webservices
Spent most of the day becoming familiar with soap4r in order to communicate with NetSuite. Turns out that the soap4r shipping with Ruby 1.8.5 is outdated and quite buggy compared to its gem counterpart. In fact, we would've saved a couple hours if we knew that was an option before we even started setting breakpoints.
WSDL2Ruby worked decently enough with NetSuite's WSDL but the generated file containing the classes (default.rb) had redundant entries, like 35 definitions for the Passport object. Next, there was an issue with some of the classes being incomplete. For example, RecordRef was:
The object we created to get the request working correctly is
Finally, calling
WSDL2Ruby worked decently enough with NetSuite's WSDL but the generated file containing the classes (default.rb) had redundant entries, like 35 definitions for the Passport object. Next, there was an issue with some of the classes being incomplete. For example, RecordRef was:
which is incorrect as it is defined as:
class RecordRef
@@schema_type = "RecordRef"
@@schema_ns = "urn:core_2_5.platform.webservices.netsuite.com"
@@schema_element = []
def initialize
end
end
<complextype name="RecordRef">
<complexcontent>
<extension base="platformCore:BaseRef">
<attribute name="internalId" type="xsd:string">
<attribute name="externalId" type="xsd:string">
<attribute name="type" type="platformCoreTyp:RecordType">
<!-- primary record internalId -->
<!-- record type -->
</attribute>
</attribute>
</attribute>
</extension></complexcontent></complextype>
The object we created to get the request working correctly is
class RecordRef
@@schema_type = "RecordRef"
@@schema_ns = "urn:core_2_5.platform.webservices.netsuite.com"
attr_accessor :internalId
attr_accessor :externalId
attr_accessor :type
def initialize(internalId = nil, externalId = nil, type = nil)
@internalId = internalId
@externalId = externalId
@type = type
end
end
Finally, calling
produced a successful response from NetSuite. However, something still seems awry with the request as the role element is not properly formed:
response = driver.login(LoginRequest.new(passport))
<n1:login xmlns:n1="urn:messages_2_5.platform.webservices.netsuite.com" xsi:type="n1:LoginRequest">
<n1:passport xmlns:n2="urn:core_2_5.platform.webservices.netsuite.com" xsi:type="n2:Passport">
<n2:email>test </n2:email>
<n2:password>test</n2:password>
<n2:account>test</n2:account>
<n2:role xsi:type="n2:RecordRef">
</n2:role>
</n1:passport>
</n1:login>
Friday, March 09, 2007
Geocoding service findings and comparison
Google Maps:
Yahoo MapService:
Note regarding accuracy statements above: I tested both services with variations on my home address which can be identified strictly by number coordinates or with the street name (Valley Sage Drive). Google's service did not find my address in any format I tried but continued to respond with varied suggestions none of which were applicable (though it stated they were the highest level of accuracy). As for yahoo, it found my address in every variation and for those that it suggested it clearly indicated a warning as an attribute of the ResultSet. Odd that Google Maps works for my address, but the geocoding service does not (and they're supposed to be integrated).
Both services provide city and state values when given a zip.
Determining valid addresses may prove to be a bit difficult given that both services "suggest" what the closest match could be.
- requires an API key
- http geocode service that'll return results in XML or JSON
- lots of documentation on javascript implementation
- issues in resolving bad addresses by suggesting alternatives and flagging them with the best accuracy-level
- comma separated values on the query string
- 50k per day limit
Yahoo MapService:
- http geocode service return results in XML or PHP
- cleaner documentation
- ApplicationID required
- address suggestion behaves more as expected and accuracy seems better
- query string attributes expected in request
- 5k per day limit
Note regarding accuracy statements above: I tested both services with variations on my home address which can be identified strictly by number coordinates or with the street name (Valley Sage Drive). Google's service did not find my address in any format I tried but continued to respond with varied suggestions none of which were applicable (though it stated they were the highest level of accuracy). As for yahoo, it found my address in every variation and for those that it suggested it clearly indicated a warning as an attribute of the ResultSet. Odd that Google Maps works for my address, but the geocoding service does not (and they're supposed to be integrated).
Both services provide city and state values when given a zip.
Determining valid addresses may prove to be a bit difficult given that both services "suggest" what the closest match could be.
Thursday, March 08, 2007
a more efficient top for OS X
echo "alias top=\"top -d -o cpu\"" >> ~/.profile
The "-d" bypasses the strain on Mach"-o cpu" and will sort by procs consuming the most CPU.
Wednesday, March 07, 2007
HttpUtility.UrlEncode, fails again
Bitten a couple months ago by the fact that System.Web.HttpUtility.UrlEncode does NOT encode ticks/single-quotes ('). How lovely. I filed a bug, someone at MS closed it out almost a month later with no explanation. It's current state is "won't fix".
Bitten again by another bug in the same function. What a shocking surprise. UrlEncode does not escape/encode the plus (+). It should encode it as %2B, but no, it doesn't, it just leaves it in the string.
Hosers.
Bitten again by another bug in the same function. What a shocking surprise. UrlEncode does not escape/encode the plus (+). It should encode it as %2B, but no, it doesn't, it just leaves it in the string.
Hosers.
Monday, February 26, 2007
Mike Heath stumbles upon pile of java JIT
Mike has had a great time with this and we've had some intriguing conversations about it. Once he posts his svn repo url I'll snag the code, run the tests on my MacBook Pro and add the results to his matrix.
Wednesday, February 21, 2007
UPS xml online tools and Ruby
UPS provides "XML Online Tools" to account holders here. Once you register as a developer you can get access to these tools and the associated specs and sample code. I needed access to the Rates and Service Selection tool, which happened to contain VB script and Java sample code from 2001. The docs are very thorough, but the code (as expected) was very outdated. Once I had it working with 1.5 (not too difficult at all) I was able to better understand what was needed for working with their HTTP-XML services.
The following barebones Ruby code is the result of a quick implementation:
The following barebones Ruby code is the result of a quick implementation:
require 'net/https'
require 'uri'
auth_xml = (access request xml doc goes here)
req_xml = (request xml doc goes here)
both_xml = auth_xml + req_xml
url = URI.parse("https://....")
request = Net::HTTP::Post.new(url.path)
request.body = (both_xml)
request.content_type = 'application/x-www-form-urlencoded'
http = Net::HTTP.new(url.host,443)
#http.set_debug_output $stderr
http.use_ssl = true
http.timeout = 30
@response = nil
http.start do
@response = http.request(request)
end
p @response.body
Wednesday, January 31, 2007
Another reason I dislike Microsoft
http://ajax.asp.net
Hooray, welcome to the Ajax world ASP.NET. It's been around long enough, someone bright in Redmond actually started the movement back in the mid 90's. But, Microsoft, could you not kill the term by branding your Ajax components as AjaxThisOrThat when it's really just a wrapper for DHTML functionality? It appears to me that you're trying to capitalize on the current wave by simply naming DHTML controls as Ajaxed controls. Which is simply wrong. Then again, I suppose that's no surprise considering your failed attempt at changing the meanings of things anyway.
Sadly, for the ASP.NET developers who may be new to it, they'll now be dumbed down (once again?) to the real concepts and essentials of what Ajax _really_ is and how/why it works.
Oh, and nice job on making it only work with web services and kudos to making configuration a breeze.
Hooray, welcome to the Ajax world ASP.NET. It's been around long enough, someone bright in Redmond actually started the movement back in the mid 90's. But, Microsoft, could you not kill the term by branding your Ajax components as AjaxThisOrThat when it's really just a wrapper for DHTML functionality? It appears to me that you're trying to capitalize on the current wave by simply naming DHTML controls as Ajaxed controls. Which is simply wrong. Then again, I suppose that's no surprise considering your failed attempt at changing the meanings of things anyway.
Sadly, for the ASP.NET developers who may be new to it, they'll now be dumbed down (once again?) to the real concepts and essentials of what Ajax _really_ is and how/why it works.
Oh, and nice job on making it only work with web services and kudos to making configuration a breeze.
Monday, January 29, 2007
Quote model, has_many and a couple hours of grief
I have two models, Quote and QuoteLineItem using the has_many and belongs_to respectively. I was having issues with AR dumping out insert statements like
This drove me nuts so I jumped into rdebug to figure out the issue. Turns out there is an ActiveRecord method name collision when using
so you have to provide an alternative, something like
Wish I knew that when I was creating this migration....
UPDATE:
http://dev.rubyonrails.org/ticket/4248
INSERT INTO quote_line_items (`created_on`, `quote_id`, `price`, `modified_on`, `product_id`, `quantity`, `modified_by_person_id`) VALUES(#<Quote:0x36551f0>,
#<Quote:0x364dba8>, #<Quote:0x3645728>, #<Quote:0x363efa4>, #<Quote:0x362ef3c>, #<Quote:0x3636728>, #<Quote:0x3624618>))
This drove me nuts so I jumped into rdebug to figure out the issue. Turns out there is an ActiveRecord method name collision when using
belongs_to :quote
so you have to provide an alternative, something like
belongs_to :related_quote, :class_name => "Quote"
Wish I knew that when I was creating this migration....
UPDATE:
http://dev.rubyonrails.org/ticket/4248
Tuesday, January 23, 2007
Spotlight and indexed content
UPDATE: Check it out: http://www.arcadianvisions.com/downloads/RubyImporter.html
Became apparent to me today as I was searching for some files that Spotlight only indexes content for files based on their extension (and plugin, if installed). I was able to confirm this with the following code:
There's a bunch of data there associated specifically to the .java extension. Find that file based on its contents:
Aha, there's the file.
Trying this again with, say, a .rb extension:
No results. mdls shows that there are some attributes associated with the .rb extension, but somehow the content isn't indexed.
XCode provides a project template called "Metadata Importer" so you can write your own to deal with custom extensions. Apple's doc explains the process.
Became apparent to me today as I was searching for some files that Spotlight only indexes content for files based on their extension (and plugin, if installed). I was able to confirm this with the following code:
echo "hello you hoser" > something.java
mdls something.java
There's a bunch of data there associated specifically to the .java extension. Find that file based on its contents:
mdfind "you hoser" |grep java
Aha, there's the file.
Trying this again with, say, a .rb extension:
echo "take off you nob" > somethingelse.rb
mdfind "take off you" | grep something
No results. mdls shows that there are some attributes associated with the .rb extension, but somehow the content isn't indexed.
XCode provides a project template called "Metadata Importer" so you can write your own to deal with custom extensions. Apple's doc explains the process.
Friday, January 12, 2007
quicksilver shortcut for locking the screen in OSX
I copied the ScreenSaverEngine.app from System/Library/Frameworks/Screensaver.framework/Versions/A/Resources/ScreenSaverEngine.app
to a cataloged QuickSilver directory. From there I just bound a key through the Triggers. Now I can lock the machine with ctl-option-l.
to a cataloged QuickSilver directory. From there I just bound a key through the Triggers. Now I can lock the machine with ctl-option-l.
Monday, January 08, 2007
Suse 10.2 64-bit and VMWare Server
Need a 64-bit server so we can run our VMWare machines on it and utilize the 8+ gig of RAM. Originally tried CentOS but because VMWare Server is compiled against 32-bit libraries, it would be a nasty amount of work to install the needed libraries one-by-one (ldd spit out at least 20 libraries we needed). After digging around online it turns out that VMWare "officially" supports Suse but not much else. Time was of the essence and we bagged Gentoo for that reason.
The 10.1 install was pleasant, but the user experience was very unpleasant. I didn't actually install it, but a coworker did and it was only a matter of days until he migrated to Ubuntu. We were hoping that some of the usability issues were resolved in 10.2, happy to report that is the case. We installed the base system, developer libraries, kernel development and the 32-bit libraries during the initial package selection. After that, once the system was up and running, vmware installed without issue.
To use vnc (via ssh) we enabled Remote Login in Login Window Preferences (not sure why that's a System Application but not in the Control Center). The command to enable port forwarding for local vncviewer execution is "ssh -g -L localhost:5901:machine:5901 user@machine -X", then "vncviewer localhost::5901" will connect right up through that ssh tunnel (also, ssh with the -g enables anyone to use your tunnel).
The 10.1 install was pleasant, but the user experience was very unpleasant. I didn't actually install it, but a coworker did and it was only a matter of days until he migrated to Ubuntu. We were hoping that some of the usability issues were resolved in 10.2, happy to report that is the case. We installed the base system, developer libraries, kernel development and the 32-bit libraries during the initial package selection. After that, once the system was up and running, vmware installed without issue.
To use vnc (via ssh) we enabled Remote Login in Login Window Preferences (not sure why that's a System Application but not in the Control Center). The command to enable port forwarding for local vncviewer execution is "ssh -g -L localhost:5901:machine:5901 user@machine -X", then "vncviewer localhost::5901" will connect right up through that ssh tunnel (also, ssh with the -g enables anyone to use your tunnel).
Subscribe to:
Posts (Atom)