Tommy Chheng

Icon

All Things Programming!

Call a JRuby method from Java

JRuby is a great way of reducing verbose Java code. Here’s a way of implementing a Java interface in JRuby and calling the method from Java.

Java Interface

We’ll start with a simple Java interface:


interface JavaInterfaceExample{
  int add(int a, int b);
}

Compile it using

javac JavaInterfaceExample.java

Implement the Java Interface in JRuby

We will implement this method in JRuby. When importing interfaces from Java code, you should use the Java namespace as in include Java::JavaInterfaceExample. The signature is important since JRuby is dynamically typed. If it isn’t specified, the parameters will be a Java Object.


require 'java'
class JrubyAdderImpl
  include Java::JavaInterfaceExample
  java_signature 'int add(int, int)'
	def add(a, b)
		a+b
	end
end

Compile it using:

jrubyc --javac -cp . JrubyAdderImpl.rb

Creating a Java class calling a JRuby method

Then let’s create a Java class which calls the jruby method:


class JavaCallerApp {
    public static void main(String[] args) {
	    JrubyAdderImpl jrubyImpl = new JrubyAdderImpl();
	    System.out.println("Adding 3+5=" + jrubyImpl.add(3,5)); // Display the string.
    }
}

Compile it:

javac -cp /usr/local/jruby/lib/jruby.jar:. JavaCallerApp.java

and run it:

java -cp /usr/local/jruby/lib/jruby.jar:. JavaCallerApp

Output:

Adding 3+5=8

Downside

While this works, it’s not a very optimally solution for calling JRuby code from Java. When you compiled JrubyAdderImpl.rb, it created a JrubyAdderImpl.java file which runs a JRuby runtime layer against the JRuby script file. I imagine this isn’t very performant.

I recommend using Duby or Scala as alternative JVM languages for greater interoperability with Java.

I placed the code on a github repo.

Gettext On Rails 3.0.0.beta: first open source task accomplished via Next Sprocket!

Great to wake up on Monday morning to see that someone has accepted and paid for the first open source task on our website Next Sprocket! Very happy to see our concept working.

The task was for making gettext rails 3.0 compatibility and providing a sample Rails 3.0 app. Check out the solution here.

If you have a gem that you need upgraded or any open source problem, please post the task on Next Sprocket. Someone will get it done and it will be an open source benefit.

MongoDB For Natural Development

Here’s the slides from a talk about MongoDB at the feb OC Ruby meetup.

MongoDB For Natural Development

There were a few examples from Tim Morgan’s presentation at the LaRubyConf2010 that resonated how ActiveRecord can be a source of many headaches. I wager this is because the ActiveRecord ORM adds complexity to mapping from ruby objects to SQL world. The mapping isn’t one to one and complexity is the unfortunate byproduct.

On the other hand, MongoDB’s data modeling naturally maps to today’s popular programming languages. Essentially, most data are hashes(or associative arrays/dictionaries) and hashes are the basic data model for MongoDB. By having such a similar data representation, the ORM complexity level is extremely minimal compared to a typical ORM designed for SQL.

So use MongoDB because it can reduce the amount of complexity and bugs in your system.

Paypal Adaptive Ruby Gem Released

I have been tinkering with the new Paypal Adaptive Payments API and created a simple ruby gem to interface with it. Still pretty new but I’m using it with little problems so far. Submit bug reports if found. See the code at github

Paypal Adaptive Payments API
The adaptive payments api gives you the opportunity to make preapproved payments, chained payments and parallel payments. The chained/parallel payments are great for commission-based apps or if you are trying to connect a buyer to multiple sellers with a single interface.

How to use with Rails:
Install:

sudo gem install paypal_adaptive

Setup your API info by adding a paypal_adaptive.yml to your config folder:


development:
  environment: "sandbox"
  username: "sandbox_username"
  password: "sandbox_password"
  signature: "sandbox_signature"
  application_id: "sandbox_app_id"

test:
  environment: "sandbox"
  username: "sandbox_username"
  password: "sandbox_password"
  signature: "sandbox_signature"
  application_id: "sandbox_app_id"

production:
  environment: "production"
  username: "my_production_username"
  password: "my_production_password"
  signature: "my_production_signature"
  application_id: "my_production_app_id"

Make the payment request:


pay_request = PaypalAdaptive::Request.new

data = {
"returnUrl" => "http://testserver.com/payments/completed_payment_request",
"requestEnvelope" => {"errorLanguage" => "en_US"},
"currencyCode"=>"USD",
"receiverList"=>{"receiver"=>
     [{"email"=>"testpp_1261697850_per@nextsprocket.com", "amount"=>"10.00"}]},
"cancelUrl"=>"http://testserver.com/payments/canceled_payment_request",
"actionType"=>"PAY",
"ipnNotificationUrl"=>"http://testserver.com/payments/ipn_notification"
}

pay_response = pay_request.pay(data)

if pay_response.success?
  redirect_to pay_response.approve_paypal_payment_url
else
  puts pay_response.errors.first['message']
  redirect_to failed_payment_url
end

Once the user goes to pay_response.approve_paypal_payment_url, they will be prompted to login to Paypal for payment.

Upon payment completion page, they will be redirected to http://testserver.com/payments/completed_payment_request.

They can also click cancel to go to http://testserver.com/payments/canceled_payment_request

The actual payment details will be sent to your server via “ipnNotificationUrl” You have to create a listener to receive POST messages from paypal. I added a Rails metal template in the templates folder which handles the callback.

Additionally, you can make calls to Paypal Adaptive’s other APIs:


payment_details, preapproval, preapproval_details,
cancel_preapproval, convert_currency, refund

Input is just a Hash just like the pay method. Refer to the Paypal Adaptive manual for more details.

Sorting a HashMap by Value in Java vs Ruby

I’m working a graph problem in Java where I need to sort nodes by its edge count. I have a HashMap of nodes to edge count so I just need to sort a HashMap by its value.
A quick Google search brought up a few solutions. Below is a snippet of a typical solution from StackOverFlow


public static > List getKeysSortedByValue(Map map) {
    final int size = map.size();
    final List> list = new ArrayList>(size);
    list.addAll(map.entrySet());
    final ValueComparator cmp = new ValueComparator();
    Collections.sort(list, cmp);
    final List keys = new ArrayList(size);
    for (int i = 0; i < size; i++) {
        keys.set(i, list.get(i).getKey());
    }
    return keys;
}
private static final class ValueComparator>
                                     implements Comparator> {
    public int compare(Map.Entry o1, Map.Entry o2) {
        return o1.getValue().compareTo(o2.getValue());
    }
}

Can you believe it?? >10 lines of verbose madness! The Ruby solution is:

>> x = {:a => 1, :b => 2, :c => 1, :d => 5}
>> x.keys.sort_by{|k| x[k]}
=> [:a, :c, :b, :d]

This makes you really appreciate closure support in languages. Java 7′s support of closure should bring more sanity to the Java world.

I’m also learning Clojure right now, the solution is just as nice as Ruby.

user=> (def x {:a 1 :b 2 :c 1 :d 5})
user=> (sort-by #(x %) (keys x))
(:a :c :b :d)

edit:
In Scala, it is also very succinct:


scala> val x = Map('a' -> 1, 'b' -> 2, 'c' -> 1, 'd' -> 5)
x: scala.collection.immutable.Map[Char,Int] = Map((a,1), (b,2), (c,1), (d,5))
scala> x.keysIterator.toList.sortWith((key1,key2) => x(key1) < x(key2))
res5: List[Char] = List(a, c, b, d)

Twitter OAuth Ruby Gem PIN-based Authentication API Change

I have been using the moomerman-twitter_oauth gem for to allow users to login to our web app via Twitter Connect. Unfortunately, it stopped working when a change in the Twitter API happened. During the OAuth authentication process, instead of being redirected back to our web app, it would show a screen that said:

"You've successfully granted access...enter the following PIN to complete the process"

After browsing the net and getting help from the Twitter API team, I learned that Twitter recently made a change to their OAuth process to allow this PIN type authentication for applications. See for more info: http://groups.google.com/group/twitter-development-talk/browse_thread/thread/472500cfe9e7cdb9/848f834227d3e64d?pli=1

The oauth ruby gem defaults to using PIN-based process instead of the regular web app redirect process. To fix this, explicitly set the oauth_callback url parameter when getting the request token:

    @twitter_client = TwitterOAuth::Client.new(
        :consumer_key => TWITTER_CONSUMER_KEY,
        :consumer_secret => TWITTER_CONSUMER_SECRET
    )
    request_token = @twitter_client.request_token(:oauth_callback => oauth_confirm_url)

If you are getting a (OAuth::Unauthorized) “401 Unauthorized” error after adding the oauth_callback parameter, try altering your oauth callback method to explicitly state the oauth_verifier as well:

  def oauth_callback
    @twitter_client = TwitterOAuth::Client.new(
        :consumer_key => TWITTER_CONSUMER_KEY,
        :consumer_secret => TWITTER_CONSUMER_SECRET
    )

    @twitter_access_token = @twitter_client.authorize(
      session[:request_token],
      session[:request_token_secret],
      :o auth_verifier =>params[:oauth_verifier]
    )

Apparently, this was posted on the Twitter API Development Group in late May, but it would have been nice if Twitter DMed every web app signed up on the twitter app list of the change. I guess this is a warning for any Twitter API consumers to follow the dev list closely..