blob: 21543b2ef2edd34dcef42aa861a4a3a0b5b22cb6 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with this
# work for additional information regarding copyright ownership. The ASF
# licenses this file to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
if RbConfig::CONFIG['host_os'] =~ /darwin/i
# On OS X we attempt to guess where JAVA_HOME is, if not set
# We set JAVA_HOME early so we can use it without calling Java.load first.
ENV['JAVA_HOME'] ||= '/System/Library/Frameworks/JavaVM.framework/Home'
end
require 'rjb'
# Equivalent to Java system properties. For example:
# ENV_JAVA['java.version']
# ENV_JAVA['java.class.version']
ENV_JAVA = {}
# Buildr runs along side a JVM, using either RJB or JRuby. The Java module allows
# you to access Java classes and create Java objects.
#
# Java classes are accessed as static methods on the Java module, for example:
# str = Java.java.lang.String.new('hai!')
# str.toUpperCase
# => 'HAI!'
# Java.java.lang.String.isInstance(str)
# => true
# Java.com.sun.tools.javac.Main.compile(args)
#
# The classpath attribute allows Buildr to add JARs and directories to the classpath,
# for example, we use it to load Ant and various Ant tasks, code generators, test
# frameworks, and so forth.
#
# When using an artifact specification, Buildr will automatically download and
# install the artifact before adding it to the classpath.
#
# For example, Ant is loaded as follows:
# Java.classpath << 'org.apache.ant:ant:jar:1.7.0'
#
# Artifacts can only be downloaded after the Buildfile has loaded, giving it
# a chance to specify which remote repositories to use, so adding to classpath
# does not by itself load any libraries. You must call Java.load before accessing
# any Java classes to give Buildr a chance to load the libraries specified in the
# classpath.
#
# When building an extension, make sure to follow these rules:
# 1. Add to the classpath when the extension is loaded (i.e. in module or class
# definition), so the first call to Java.load anywhere in the code will include
# the libraries you specify.
# 2. Call Java.load once before accessing any Java classes, allowing Buildr to
# set up the classpath.
# 3. Only call Java.load when invoked, otherwise you may end up loading the JVM
# with a partial classpath, or before all remote repositories are listed.
# 4. Check on a clean build with empty local repository.
module Java
module Package #:nodoc:
def method_missing(sym, *args, &block)
raise ArgumentError, 'No arguments expected' unless args.empty?
name = "#{@name}.#{sym}"
return ::Rjb.import(name) if sym.to_s =~ /^[[:upper:]]/
::Java.send :__package__, name
end
end
class << self
# Returns the classpath, an array listing directories, JAR files and
# artifacts. Use when loading the extension to add any additional
# libraries used by that extension.
#
# For example, Ant is loaded as follows:
# Java.classpath << 'org.apache.ant:ant:jar:1.7.0'
def classpath
@classpath ||= begin
classpath = []
class << classpath
def new_add(*args)
warn 'Java is already loaded' if Java.loaded?
send(:old_add, *args)
end
alias_method :old_add, :<<
alias_method :<<, :new_add
end
classpath
end
end
# Returns true if the JVM is loaded with all the libraries loaded on the classpath.
def loaded?
@loaded
end
# Most platforms requires tools.jar to be on the classpath, tools.jar contains the
# Java compiler (OS X and AIX are two exceptions we know about, may be more).
# Guess where tools.jar is from JAVA_HOME, which hopefully points to the JDK,
# but maybe the JRE. Return nil if not found.
def tools_jar #:nodoc:
@tools_jar ||= begin
home = ENV['JAVA_HOME'] or fail 'Are we forgetting something? JAVA_HOME not set.'
['lib/tools.jar', '../lib/tools.jar'].map { |path| File.expand_path(path, home) }.
find { |path| File.exist?(path) }
end
end
# Loads the JVM and all the libraries listed on the classpath. Call this
# method before accessing any Java class, but only call it from methods
# used in the build, giving the Buildfile a chance to load all extensions
# that append to the classpath and specify which remote repositories to use.
def load
return self if @loaded
classpath << tools_jar if tools_jar
classpath.map! { |path| Proc === path ? path.call : path }
cp = Buildr.artifacts(classpath).map(&:to_s).each { |path| file(path).invoke }
java_opts = (ENV['JAVA_OPTS'] || ENV['JAVA_OPTIONS']).to_s.split
# Prepend the JDK bin directory to the path under windows as RJB can have issues if it picks
# up jvm dependencies from other products installed on the system
if Buildr::Util.win_os?
ENV["PATH"] = "#{ENV['JAVA_HOME']}#{File::SEPARATOR}bin#{File::PATH_SEPARATOR}#{ENV["PATH"]}"
end
::Rjb.load cp.join(File::PATH_SEPARATOR), java_opts
props = ::Rjb.import('java.lang.System').getProperties
enum = props.propertyNames
while enum.hasMoreElements
name = enum.nextElement.toString
ENV_JAVA[name] = props.getProperty(name)
end
@loaded = true
self
end
def method_missing(sym, *args, &block) #:nodoc:
raise ArgumentError, 'No arguments expected' unless args.empty?
Java.load # need to load RJB's classpath now!
name = sym.to_s
return ::Rjb.import(name) if name =~ /^[[:upper:]]/
__package__ name
end
private
def __package__(name) #:nodoc:
Module.new.tap do |m|
m.extend Package
m.instance_variable_set :@name, name
end
end
end
end
class Array #:nodoc:
# Converts a Ruby array into a typed Java array, argument specifies the element type.
# This is necessary for JRuby and causes no harm on RJB.
def to_java(cls)
map { |item| cls.new(item) }
end
end