I have been doing some site scraping of late. And as a result, I have really come to appreciate the semantic web. It’d make life infinitely easier for grabbing data. Of course there are other, better reasons for using the semantic web, but right now, it’d make a difference in my life.
Oct 07
Dear Mr. Designer
Generally, if you are working with an external library, such as yui, it’s not a good idea to override the css for a widget’s css class. That means that every instance of the widget will have that property, whether you want it to or not. Moreover, it means that in order to fix it, you need to find and override every instance of the widget.
‘k thx bye
Sep 25
JBoss run.sh may be harmful
A coworker and I discovered an issue with jboss’ run.sh (which starts the app server). The problem lies in different flavours of unix (or unix-like) shells returning different values for wait
.
The relevant code is:
1 2 3 4 5 6 7 |
# Wait until the background process exits WAIT_STATUS=0 while [ "$WAIT_STATUS" -ne 127 ]; do JBOSS_STATUS=$WAIT_STATUS wait $JBOSS_PID 2>/dev/null WAIT_STATUS=$? done |
This is all well and good in linux — redhat uses /bin/bash
and ubuntu uses /bin/dash
for /bin/sh
— both of which return 127 when waiting for a process which does not exist. However, Solaris’ /bin/sh
returns 0 (/bin/ksh
returns 127).
So, the run.sh goes into an infinite loop, thrashing, badly. CPU gets pegged and all that fun stuff.
How to fix? Well in order to make it OS/shell dependant, we’ll determine the value which is returned by wait when a process does not exist. We’re guaranteed that there is one process id which won’t be used in unix — 0. So, we wait on PID 0, and use the return value, $?
to determine how the environment handles the wait. The “fixed” code looks like:
1 2 3 4 5 6 7 8 9 |
wait 0 2>/dev/null NO_SUCH_PID=$? # Wait until the background process exits WAIT_STATUS=0 while [ "$WAIT_STATUS" -ne $NO_SUCH_PID ]; do JBOSS_STATUS=$WAIT_STATUS wait $JBOSS_PID 2>/dev/null WAIT_STATUS=$? done |
EDIT:
This was fixed in 4.2.3 GA with the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# Wait until the background process exits WAIT_STATUS=128 while [ "$WAIT_STATUS" -ge 128 ]; do wait $JBOSS_PID 2>/dev/null WAIT_STATUS=$? if [ "${WAIT_STATUS}" -gt 128 ]; then SIGNAL=`expr ${WAIT_STATUS} - 128` SIGNAL_NAME=`kill -l ${SIGNAL}` echo "*** JBossAS process (${JBOSS_PID}) received ${SIGNAL_NAME} signal. ***" >&2 fi done if [ "${WAIT_STATUS}" -lt 127 ]; then JBOSS_STATUS=$WAIT_STATUS else JBOSS_STATUS=0 fi |
Sep 22
JRuby + jmx4r + rrd4j == Easy reporting on app servers (part I)
This is a how-to for using jmx and rrd4j, a java implementation of rrdtool, to report on app server statistics.
Thanks to Jeff Mesnil(author of jmx4r), Werner Schuster (JMX the Ruby way with jmx4r), sishen (JRobin sucks), and the rrd4j team.
You’ll need the following:
- JVM 1.5 or higher — JRE is not enough, you also need the JDK. Remember to set your
JAVA_HOME
— JRuby needs it. - JRuby — I’m using 1.1.4. Note: You need to be sure to set the
JRUBY_HOME
and make sure that${JRUBY_HOME}/bin
comes in$PATH
prior to any other ruby installation. Otherwise, your results will be indeterminate. - jmx4r — this is a gem and can be installed by
1jruby -S gem install jmx4r - rrd4j — in order to get this, you need to create an account on java.net. Once you’ve done that, you can download the library via subversion:
1svn co https://rrd4j.dev.java.net/svn/rrd4j/trunk rrd4j --username <em>username</em>
Replaceusername
with your java.net username. You’ll need ant to build it:
1cd rrd4j/rrd4j; ant
Or you can download the jars: rrd4j jars - An application which responds to jmx queries — this example is using jconsole since it is a standard part of the java distribution in 1.5 and after.
Before we do much else, let’s verify that jconsole is working:
1 |
jconsole -J-Dcom.sun.management.jmxremote.port=64850 -J-Dcom.sun.management.jmxremote.authenticate=false -J-Dcom.sun.management.jmxremote.ssl=false |
Choose for the port some large nuimber… Your screen will look something like this for 1.5 (ignore the cutoff bits, I’m writing this on chibi):
Ok, now that we’ve got that going, let’s attempt connecting via jmx4r…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
$ jruby -S jirb irb(main):001:0> require 'rubygems' => true irb(main):002:0> require 'jmx4r' => true irb(main):003:0> require 'java' => false irb(main):004:0> JMX::MBean.establish_connection :host => "localhost", :port => 64850 => #<#:0x1bd06a0 @java_object=javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection@12f9ee1> irb(main):005:0> memory =JMX::MBean.find_by_name "java.lang:type=Memory" => #"NonHeapMemoryUsage", "verbose"=>"Verbose", "object_pending_finalization_count"=>"ObjectPendingFinalizationCount", "heap_memory_usage"=>"HeapMemoryUsage"}, @mbsc=#<#:0x1bd06a0 @java_object=javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection@12f9ee1>, @operations={"gc"=>["gc", []]}, @object_name=#> irb(main):006:0> memory.heap_memory_usage => # irb(main):012:0> memory.heap_memory_usage.keys => #<#:0x129dcc0 @java_object=[committed, init, max, used]> irb(main):015:0> memory.heap_memory_usage.to_s => "javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=java.lang.management.MemoryUsage,items=((itemName=committed,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=init,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=max,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=used,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)))),contents={committed=7569408, init=0, max=66650112, used=3952968})" irb(main):020:0> memory.heap_memory_usage["committed"] => 7569408 irb(main):021:0> #trigger a gc irb(main):022:0* memory.gc => nil irb(main):023:0> memory =JMX::MBean.find_by_name "java.lang:type=Memory" => #"NonHeapMemoryUsage", "verbose"=>"Verbose", "object_pending_finalization_count"=>"ObjectPendingFinalizationCount", "heap_memory_usage"=>"HeapMemoryUsage"}, @mbsc=#<#:0x1bd06a0 @java_object=javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection@12f9ee1>, @operations={"gc"=>["gc", []]}, @object_name=#> irb(main):024:0> memory.heap_memory_usage["committed"] => 7569408 irb(main):026:0> memory.heap_memory_usage["max"] => 66650112 irb(main):027:0> memory.heap_memory_usage["used"] => 4210824 irb(main):028:0> exit $ |
Cool! now we’re making progress!
Sep 22
JRuby to check connectivity…
I had an issue reported by a developer where their jboss connection pool wasn’t working properly. It looked good to me, so I decided to verify that everything worked in so far as connectivity from the box. So, I used the following jruby script to help:
1 2 3 4 5 6 7 8 9 10 11 12 |
require 'rubygems' require 'jdbc' require 'java' Java::oracle.jdbc.driver.OracleDriver url = "jdbc:oracle:thin:@SERVER:1521:DB" user = "user" pass = "pass" conn = java.sql.DriverManager.get_connection(url,user,pass) stmt = conn.create_statement query = "select 1 from dual" rss = stmt.execute_query(query) puts rss.next? # did we get anything? |
Sep 17
Digging out
Columbus, OH got hit with the remnants of Ike. Large segments still don’t have power (and won’t fora while).
So, connectivity is really spotty & I’m behind in a big way. So, if you’ve commented and it’s not been approved or is not replied to, please understand.
Sep 12
Class is Class, and Instance, Instance, and never the twain shall meet
More about methods, it’s inspired/spurred by a comment on methods, public_methods, and private_methods by Pit Captain. It also corrects some misconceptions I had (and may have (wrongly) given others).
I’ve added a new category, “eating crow” for this and any other postings where I step back and re-evaluate my posts. This is to keep me honest, and, if y’all would, please feel free to tell me when it’s time to “eat crow”.
Sep 11
universal cat redux
I have a neglectful relationship with inject
. That is, I neglect to remember that it exists, having worked for so long with other languages which are “unfamiliar with the concept”. Amos King’s blog entry on Inject & Me – BFFs got me to thinking that ucat (see cat on steroids (or cat on a hot ruby roof)) could use inject
as opposed to the each_byte
. So, instead of
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def non_printing(line) proc = "" line.each_byte do |c| proc += case c when (0 .. 8): "^#{(c + 64).chr}" when (10 .. 11): "^#{(c + 64).chr}" when (13 .. 26): "^#{(c + 64).chr}" when (27 .. 31): "^#{%w([ \\ ] ^ _)[c - 27]}" when 127: "^?" when ((c & 128) == 128): "M-0#{c.to_s(8)}" else c.chr end end proc end |
I can do:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def non_printing(line) line.split("").map{|c|c[0]}.inject("") do |s,c| s += case c when (0 .. 8): "^#{(c + 64).chr}" when (10 .. 11): "^#{(c + 64).chr}" when (13 .. 26): "^#{(c + 64).chr}" when (27 .. 31): "^#{%w([ \\ ] ^ _)[c - 27]}" when 127: "^?" when ((c & 128) == 128): "M-0#{c.to_s(8)}" else c.chr end end end |
I still think there needs to be a better way — going from string to an array of strings mapped to an array of bytes so that I can process it via inject seems to be awkward. So, I do some searching and find Object#enum_for
(let me plug gotAPI — it’s a great tool for searching a large number of API’s) and come up with:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def non_printing(line) line.enum_for(:each_byte).inject("") do |s,c| s += case c when (0 .. 8): "^#{(c + 64).chr}" when (10 .. 11): "^#{(c + 64).chr}" when (13 .. 26): "^#{(c + 64).chr}" when (27 .. 31): "^#{%w([ \\ ] ^ _)[c - 27]}" when 127: "^?" when ((c & 128) == 128): "M-0#{c.to_s(8)}" else c.chr end end end |
That seems cleaner to me. One of the things I love about ruby is that there’s usually more way than one to do something. And it’s often quicker, like in Unix, to go with what you know rather than making it more elegant. However, I also like that it’s easy to write elegant code.
And elegant code is a thing of beauty.
You can download the updated version of ucat.rb (you may need to rename it to ucat.rb)
Sep 10
cat on steroids (or cat on a hot ruby roof)
I got to thinking about SuperIO and how it could be used as a swiss army chainsaw to open files, whereever they might be on the net. From there, my fevered mind got to thinking about cat and how the two could be used together. That said, I present ucat — a universal cat, if you will, which does not need to be herded, but rather will do as you ask. It’s expecting to be able to find SuperIO, so you’ll need to make it available.