Friday, May 22, 2009

Ruby-Processing and java.lang.ExceptionInInitializerError

rp5 run samples/jwishy.rb 
RubyGlobal.java:135:in `createGlobals': java.lang.ExceptionInInitializerError
    from Ruby.java:939:in `init'
    from Ruby.java:172:in `newInstance'
    from Main.java:199:in `run'
    from Main.java:110:in `run'
    from Main.java:94:in `main'
... the culprit was the alternative version of the JRE I was using (OpenJDK). After swtiching to the standard Sun JDK everything worked fine.

Saturday, April 18, 2009

Golem Statemachine

Following a frustrating week with the acts_as_state_machine/AASM plugin, I ended up writing my own finite state machine library for Ruby.

It's called Golem, and it's now on Github, here: http://github.com/zuk/golem_statemachine/tree/master

The code is cleaner than AASM's (or at least I think so), which should make debugging less frustrating. There's also a nice DSL for defining the state machine.

For example, to implement this statemachine:

You would define it like so:

define_statemachine do
  initial_state :HUNGRY

  state :HUNGRY do
    on :eat do
      transition :to => :SATIATED, :if => :likes?
      transition do
        action do |monster| 
          puts "#{monster} says BLAH!!"
        end
      end
    end
  end

  state :SATIATED do
    enter do |monster|
      puts "#{monster} says BURP!!!"
    end
  end
end

The state machine definition goes inside your Ruby class (or ActiveRecord model), endowing the class with finite state machine behavior:

require 'golem'

class Monster
  include Golem

  attr_accessor :state

  def initialize(name)
    @name = name
  end

  def to_s
    @name
  end

  def likes?(food)
    food.kind_of?(String)
  end

  define_statemachine do
    # ...
  end
end

m = Monster.new("Stringosaurus")
puts m.current_state # ==> :HUNGRY
m.eat(12345)         # ==> "Stringosaurus says BLAH!!"
puts m.current_state # ==> :HUNGRY
m.eat("abcde")       # ==> "Stringosaurus says BURP!!"
puts m.current_state # ==> :SATIATED

Monday, February 9, 2009

python-xml woes

Python ImportErrors like the following (stemming from the recent deprecation of the python-xml library in Ubuntu):
Failed to load application: No module named ext
... can be easily addressed by:
sudo apt-get install python-xml
export PYTHONPATH=$PYTHONPATH:/usr/lib/python2.5/site-packages/oldxml
This caused me a good few hours' grief earlier today.

Wednesday, November 12, 2008

A PHP Client for JasperServer (via SOAP)

I needed a PHP version of my Ruby SOAP client for JaserpServer.

Here it is: http://gist.github.com/26205

Usage (this runs the report unit '/my_report' and returns the result in PDF format):

 
  $jasper_url = "http://jasper.example.com/jasperserver/services/repository";
  $jasper_username = "jasperadmin";
  $jasper_password = "topsecret";


  $client = new JasperClient($jasper_url, $jasper_username, $jasper_password);

  $report_unit = "/my_report";
  $report_format = "PDF";
  $report_params = array('foo' => 'bar', 'fruit' => 'apple');
 
  $result = $client->requestReport($report_unit, $report_format,$report_params);

  header('Content-type: application/pdf');
  echo $result;

Thursday, October 23, 2008

gittidy

I had my first run in with git today. After trying to sync an out-of-whack git-svn local repo with github things turned ugly:

git push
error: remote 'refs/heads/master' is not a strict subset of local ref 'refs/heads/master'. maybe you are not up-to-date and need to pull first?
error: failed to push to 'git@github.com:gunark/rubycas-server.git'

Turns out that remotely deleting the master branch on github (as described here) and then recreating it fixed the problem:

git push origin :heads/master
deleting 'refs/heads/master'
Everything up-to-date
git push origin master
updating 'refs/heads/master'
  from 0000000000000000000000000000000000000000
  to   6dd64b1b025c324d0b287805d6c18183b9f20b9e
Generating pack...
Done counting 1395 objects.
Deltifying 1395 objects...
 100% (1395/1395) done
Writing 1395 objects...
 100% (1395/1395) done
Total 1395 (delta 960), reused 0 (delta 0)

Yay

There was some weirdness in the github project page after this, but performing another commit and push seems to have taken things back to normal.

Wednesday, October 15, 2008

WS-Management + Openwsman + openSUSE + Ruby

Yet another failed attempt at using SNMP for monitoring application-level services led me to WS-Management, an HTTP/SOAP-based protocol meant to replace SNMP. DS-Management might not be the first protocol to attempt usurping SNMP, but this one looks promising. Widespread support and implementation is claimed by Microsoft, and a reasonably mature open-source implementation -- Openwsman -- is sponsored by SuSE.

Documentation for Openwsman unfortunately seems rather lacking. It took some poking around, but I was able to get a basic client-server session going under openSUSE 10.3. Here's how:

First, add the development channel for openwsman and install the openwsman packages:

sudo smart channel --add http://download.opensuse.org/repositories/home:/kwk:/Management/openSUSE_10.3/home:kwk:Management.repo
sudo smart update home_kwk_Management
sudo smart install openwsman openwsman-client openwsman-server wsmancli openwsman-yast
If you run into PGP key problems, try disabling PGP key checking first:
smart config --set rpm-check-signatures=false

The openwsman-server package installs openwsmand -- a stand-alone server providing WS-Management services. We'll need to configure the authentication system before running the server. I was unable to get things going with the default Basic authentication, but Digest worked for me:

htdigest2 -c /etc/openwsman/digest_auth.passwd OPENWSMAN admin
Adding password for admin in realm OPENWSMAN.
New password: test
Re-type new password: test

Now edit the Openwsman config file to use Digest authentication. The config file is under /etc/openwsman/openwsman.conf and should be altered to look something like this (note that we've uncommented the 'digest_password_file' option):

[server]
port = 8889
#ssl_port = 8888
ssl_cert_file = /etc/openwsman/servercert.pem
ssl_key_file = /etc/openwsman/serverkey.pem
digest_password_file = /etc/openwsman/digest_auth.passwd
#basic_password_file = /etc/openwsman/simple_auth.passwd

min_threads = 4
max_threads = 10

#use_digest is OBSOLETED, see below.

#
# Authentication backend for BASIC authentication. Default is to read a configuration file defined with 'basic_password_file'
#

basic_authenticator = libwsman_pam_auth.so
basic_authenticator_arg = openwsman


[client]
port = 8889
agent = openwsman 0.6.0

#
# settings for the CIM plugin
#

[cim]
default_cim_namespace = root/cimv2

# The following are in part fake namespaces for some publicly available CIM implementations.
vendor_namespaces = OpenWBEM=http://schema.openwbem.org/wbem/wscim/1/cim-schema/2,Linux=http://sblim.sf.net/wbem/wscim/1/cim-schema/2,OMC=http://schema.omc-project.org/wbem/wscim/1/cim-schema/2

# CIMOM host, default is localhost
# host = localhost

# CIMOM port, default is 5988
# port = 5988

Okay, now we can run the server:

sudo /usr/sbin/openwsmand -d

We can now connect to the server using a few simple Ruby commands. Open an interactive ruby session (using irb) and enter the following:

require 'rwsman'
client = WsMan::Client.new('http', 'localhost', 8889, '/wsman', 'admin', 'test')
client_opt = WsMan::ClientOption.new
identify = client.identify(client_opt)
puts identify.rawxml
If everything worked, you should get a response that looks something like this:


 
 
   
     http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
     Openwsman Project
     1.5.9
   
 

The identify object returned by the client also exposes product_version, protocol_version, and product_vendor methods that return their respective values from the parsed XML data.

With the YAST plugin installed, Openwsman can access diagnostic information about your SuSE system. For example try this:

client_opt.property_add('ycp', '{ import "SuSERelease"; return SuSERelease::ReleaseInformation("/"); }' )
result = client.invoke('http://schema.opensuse.org/YaST/wsman-schema/10-3/YCP', 'eval', client_opt)
puts "SUSE Version: #{result.body}"