#!/usr/bin/env ruby
#
# = Rejb - Support for calling Enterprise Java Beans (EJBs) from JRuby
#
#   $LastChangedDate: 2006-04-13 14:50:30 -0700 (Thu, 13 Apr 2006) $
#   $LastChangedRevision: 12 $
#   $LastChangedBy: danny $
#   $HeadURL: file:///home/rubyenrails/svn/rubyenrails/public/modules/rejb/rejb.rb $
#
# == Introduction
#
# EJBs can be called from a JRuby script by calling the usual JDNI lookup
# sequence and obtaining an local interface to the EJB. This has been
# encapsulated in this mixin.
#
# == Notes
#
# * You will need JRuby to use this module.
# * For more information about jndi.properties files, see
#   http://java.sun.com/j2se/1.4.2/docs/guide/jndi/spec/jndi/jndi.6.html#pgfId=1000880.
#   The contents of a JNDI properties file are application server vendor
#   specific. Consult your local Java guru.
# * To get this working, you will have to get your CLASSPATH right. This is an
#   environment variable containing all the Java libraries you will need for
#   calling EJBs in general, and your EJB specifically. This is also vendor
#   specific. Examples below.
#
# == Examples
#
# An EJB registered under the JNDI name 'business-ejb-jndi-name', with a
# method 'someBusinessMethod' can be used like this:
#   require 'rejb'
#   business_ejb = Rejb::ejb("business-ejb-jndi-name")
#   result = business_ejb.someBusinessMethod(parameters)
#
# This assumes that you have a jndi.properties file in the same directory as
# your script. You can optionally specify the pathname to your jndi.properties
# file before calling the EJB, like this:
#   Rejb::set_jndi_properties '/bla/bla/jndi.properties'
# Besides a file name, you can also pass a Hash containing the JNDI properties,
# or a java.util.Properties object.
#
# === BEA CLASSPATH
#
# * bea/weblogic81/server/lib/weblogic.jar
# * An EJB client jar for your EJB, containing the local home interface.
#
# === JBoss CLASSPATH
#
# * jboss/server/default/lib/jboss-j2ee.jar
# * jboss/server/default/lib/jboss.jar
# * jboss/lib/jboss-common.jar
# * jboss/client/jboss-common-client.jar
# * jboss/client/jnp-client.jar
# * jboss/client/jboss-client.jar
# * jboss/client/jbossall-client.jar
# * An EJB client jar for your EJB, containing the local home interface.
#
# == License
#
# Version: CPL 1.0/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Common Public
# License Version 1.0 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.eclipse.org/legal/cpl-v10.html
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# Copyright (C) 2006 Danny Lagrouw <danny@dannynet.net>
# 
# Alternatively, the contents of this file may be used under the terms of
# either of the GNU General Public License Version 2 or later (the "GPL"),
# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the CPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the CPL, the GPL or the LGPL.
#

require 'java'

# Generic includes for using EJBs
include_class 'java.util.Properties'
include_class 'javax.naming.Context'
include_class 'javax.naming.InitialContext'
include_class 'java.io.FileInputStream'

# Module for calling EJBs from Ruby. To be used with JRuby.
# Example:
#   require 'rejb'
#   Rejb::set_jndi_properties '/bla/bla/jndi.properties' # optional!
#   business_ejb = Rejb::ejb("business-ejb-jndi-name")
#   result = business_ejb.someBusinessMethod(parameters)
module Rejb
  # Holds the initial context, once set up.
  @@context = nil

  # The default location for jndi.properties (current directory).
  @@jndi_properties = 'jndi.properties'

  # Sets JNDI properties to be used for getting an initial context. If not set,  
  # the default ('jndi.properties') is used.
  # Examples:
  # Call with a String, the jndi.properties filename:
  #   set_jndi_properties '/bla/bla/bla/jndi.properties'
  # Call with a Hash:
  #   include_class 'javax.naming.Context'
  #   set_jndi_properties({
  #     Context::INITIAL_CONTEXT_FACTORY => "weblogic.jndi.WLInitialContextFactory",
  #     Context::PROVIDER_URL => "t3://localhost:7001"})
  # Call with a java.util.Properties:
  #   include_class 'java.util.Properties'
  #   include_class 'javax.naming.Context'
  #   properties = Properties.new
  #   properties.put(Context::INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory")
  #   properties.put(Context::PROVIDER_URL, "t3://localhost:7001")
  #   set_jndi_properties properties
  def set_jndi_properties(jndi_properties)
    @@jndi_properties = jndi_properties
  end

  # Returns EJB with the specified JNDI name. Reuses initial context if
  # previously acquired.
  # Example:
  #   business_ejb = ejb("business-ejb-jndi-name")
  #   result = business_ejb.someBusinessMethod(parameters)
  def ejb(jndi_name)
    @@context ||= self.initial_context
    home = @@context.lookup(jndi_name)
    home.create
  end

  # Sets up an initial context that can be used for looking up JNDI names. For
  # internal use only.
  def self.initial_context()
    properties = Properties.new
    if @@jndi_properties.is_a? String
      if File.exist?(@@jndi_properties)
        properties.load(FileInputStream.new(@@jndi_properties))
      else
        raise IOError, 'File "' + @@jndi_properties + '" not found'
      end
    elsif @@jndi_properties.is_a? Hash
      @@jndi_properties.each do |key, value|
        properties.put(key, value)
      end
    elsif @@jndi_properties.is_a? Properties
      properties = @@jndi_properties
    else
      raise 'Called without a String (filename), Hash (set of properties) or java.util.Properties'
    end
  
    @@context = InitialContext.new(properties)
  end

  module_function :set_jndi_properties, :ejb

end
