Permalink
Browse files

* add jruby-classloader wrapper to allow reload of ruby classes which…

… became_java!

* added option to adapter to use the wrapper classloader or not to use it
  • Loading branch information...
1 parent 8b56a7f commit f713bd8374140faaed08a3c85e7eaa410e19ea75 @mkristian committed Oct 10, 2011
View
7 Mavenfile
@@ -24,8 +24,6 @@ packaging 'java-gem'
build.final_name '${project.artifactId}_ext'
-plugin(:gem).configuration[:includeOpenSSL] = false
-
profile(:transient) do |t|
t.plugin(:rspec).configuration[:specSourceDirectory] = 'spec/transient'
end
@@ -37,3 +35,8 @@ end
profile(:dm) do |t|
t.plugin(:rspec).configuration[:specSourceDirectory] = 'spec/dm_core'
end
+
+execute_in_phase(:initialize) do
+ require 'fileutils'
+ FileUtils.cp("dm-hibernate-adapter.gemspec.pom", "pom.xml")
+end
View
10 dm-hibernate-adapter.gemspec
@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
-# create by maven - leave it as is
+require 'fileutils'
Gem::Specification.new do |s|
s.name = 'dm-hibernate-adapter'
- s.version = '0.2pre'
+ s.version = '0.3pre'
s.summary = 'dm-hibernate-adapter'
s.authors = ['Douglas Ferreira', 'Kristian Meier', 'Piotr Gęga']
s.email = ['douglasrodrigo@gmail.com', 'm.kristian@web.de', 'piotrgega@gmail.com']
s.platform = 'java'
+
+ # copy the jar file into place !!!
+ FileUtils.cp('target/dm-hibernate-adapter_ext.jar', 'lib')
+
s.files = Dir['lib/dm-hibernate-adapter_ext.jar']
s.files += Dir['lib/dm-hibernate-adapter.rb']
s.files += Dir['lib/**/*']
@@ -23,7 +27,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'yard', '0.5.3'
s.add_development_dependency 'rake', '0.9.2'
s.add_development_dependency 'rspec', '1.3.0'
- s.add_development_dependency 'ruby-maven', '0.8.3.0.3.0.28.1'
+ s.add_development_dependency 'ruby-maven', '3.0.3.0.28.5'
s.add_development_dependency 'jruby-openssl', '0.7.4'
s.requirements << File.read('Mavenfile')
end
View
8 lib/dm-hibernate-adapter.rb
@@ -16,12 +16,6 @@
require 'java'
require 'jruby/core_ext'
-begin
- require 'dm-hibernate-adapter_ext.jar'
-rescue LoadError
- warn "missing extension jar, may be it is already in the parent classloader"
-end
-
require 'slf4r'
require 'slf4r/java_logger'
@@ -73,11 +67,13 @@ def initialize(name, options = {})
password = options.delete(:password)
driver = options.delete(:driver) || DRIVERS[dialect.to_sym]
pool_size = options.delete(:pool_size) || "1"
+ reload = options.delete(:allow_reload)
url = options.delete(:url)
url += "jdbc:" unless url =~ /^jdbc:/
super(name, options)
+ Hibernate.allow_reload = reload
Hibernate.dialect = Hibernate::Dialects.const_get(dialect.to_s)
Hibernate.current_session_context_class = "thread"
View
95 lib/dm-hibernate-adapter/hibernate.rb
@@ -13,12 +13,21 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+begin
+ require 'dm-hibernate-adapter_ext.jar'
+rescue LoadError
+ warn "missing extension jar, may be it is already in the parent classloader"
+end
+
+java_import 'dm_hibernate_adapter.JRubyClassLoader'
+
module Hibernate
@@mapped_classes = {}
# java_import: http://jira.codehaus.org/browse/JRUBY-3538
java_import org.hibernate.cfg.AnnotationConfiguration
+
JClass = java.lang.Class
JVoid = java.lang.Void::TYPE
@@ -76,6 +85,14 @@ def self.connection_pool_size
config.get_property "hibernate.connection.pool_size"
end
+ def self.allow_reload=(allow)
+ @allow = allow
+ end
+
+ def self.allow_reload
+ @allow || false
+ end
+
class PropertyShim
def initialize(config)
@@ -157,10 +174,10 @@ def self.config
@@config ||= AnnotationConfiguration.new
end
- def self.add_model(model_java_class, name)
- unless mapped? name
+ def self.add_model(model_java_class, model)
+ unless mapped? model
config.add_annotated_class model_java_class
- @@mapped_classes[name] = true
+ @@mapped_classes[model.name] = model.hash
@@logger.debug " model/class #{model_java_class} registered successfully"
else
@@logger.debug " model/class #{model_java_class} registered already"
@@ -169,8 +186,11 @@ def self.add_model(model_java_class, name)
private
- def self.mapped?(name)
- @@mapped_classes[name]
+ def self.mapped?(model)
+ if @@mapped_classes[model.name] && @@mapped_classes[model.name] != model.hash && self.allow_reload
+ reset_config
+ end
+ @@mapped_classes[model.name] == model.hash
end
module Model
@@ -190,20 +210,8 @@ def self.included(model)
model.extend(ClassMethods)
-# this part is needed for the model A.create method to work
-# model.class_eval <<-EOF
-# alias :initialize_old :initialize
-# def initialize(*args)
-# if self.class.hibernate!
-# self.class.new(*args)
-# else
-# initialize_old(*args)
-# end
-# end
-# EOF
-
- unless model.mapped?
- [:auto_migrate!, :auto_upgrade!, :create, :all, :copy, :first, :first_or_create, :first_or_new, :get, :last, :load].each do |method|
+ unless Hibernate.mapped?(model)
+ [:auto_migrate!, :auto_upgrade!, :create, :all, :copy, :first, :first_or_create, :first_or_new, :get, :last, :load, :new].each do |method|
model.before_class_method(method, :hibernate!)
end
@@ -245,9 +253,7 @@ def to_java_class_name
end
def hibernate!
- result = false
-
- unless mapped?
+ unless Hibernate.mapped?(self)
discriminator = nil
relationships.each do |relationship|
@@ -271,18 +277,27 @@ def hibernate!
end
add_class_annotation annotation
- Hibernate.add_model become_java!(false), name
- result = true
+ reload = Hibernate.allow_reload
+ Hibernate.add_model(become_java!(reload), self)
+
+ if reload
+
+ unless java.lang.Thread.currentThread.context_class_loader.is_a? JRubyClassLoader
+ cl = java.lang.Thread.currentThread.context_class_loader
+ if cl.is_a? org.jruby.util.JRubyClassLoader
+ java.lang.Thread.currentThread.context_class_loader = JRubyClassLoader.new(cl)
+ else
+ java.lang.Thread.currentThread.context_class_loader = 'TODO'
+ end
+ end
+
+ java.lang.Thread.currentThread.context_class_loader.register(java_class)
+ end
@@logger.debug "become_java! #{java_class}"
else
@@logger.debug "become_java! fired already #{java_class}"
end
- result
- end
-
- def mapped?
- Hibernate.mapped? name
end
private
@@ -342,49 +357,49 @@ def add_java_property(prop)
# to consider: in my opinion those methods should set from/get to java objects...
if (type == DataMapper::Property::Date)
class_eval <<-EOT
- def #{set_name.intern} (d)
+ def #{set_name.intern}(d)
attribute_set(:#{name} , d.nil? ? nil : Date.civil(d.year + 1900, d.month + 1, d.date))
end
EOT
class_eval <<-EOT
- def #{get_name.intern}
+ def #{get_name.intern}
d = attribute_get(:#{name} )
org.joda.time.DateTime.new(d.year, d.month, d.day, 0, 0, 0, 0).to_date if d
end
EOT
elsif (type == DataMapper::Property::DateTime)
class_eval <<-EOT
- def #{set_name.intern} (d)
+ def #{set_name.intern}(d)
attribute_set(:#{name} , d.nil? ? nil : DateTime.civil(d.year + 1900, d.month + 1, d.date, d.hours, d.minutes, d.seconds))
end
EOT
class_eval <<-EOT
- def #{get_name.intern}
- d = attribute_get(:#{name} )
+ def #{get_name.intern}
+ d = attribute_get(:#{name})
org.joda.time.DateTime.new(d.year, d.month, d.day, d.hour, d.min, d.sec, 0).to_date if d
end
EOT
elsif (type.to_s == BigDecimal || type == DataMapper::Property::Decimal)
class_eval <<-EOT
- def #{set_name.intern} (d)
+ def #{set_name.intern}(d)
attribute_set(:#{name} , d.nil? ? nil :#{type}.new(d.to_s))
end
EOT
class_eval <<-EOT
- def #{get_name.intern}
- d = attribute_get(:#{name} )
+ def #{get_name.intern}
+ d = attribute_get(:#{name})
java.math.BigDecimal.new(d.to_i) if d
end
EOT
else
class_eval <<-EOT
- def #{set_name.intern} (d)
+ def #{set_name.intern}(d)
attribute_set(:#{name} , d)
end
EOT
class_eval <<-EOT
- def #{get_name.intern}
- d = attribute_get(:#{name} )
+ def #{get_name.intern}
+ d = attribute_get(:#{name})
d
end
EOT
View
287 pom.xml
@@ -0,0 +1,287 @@
+<project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>rubygems</groupId>
+ <artifactId>dm-hibernate-adapter</artifactId>
+ <version>0.3pre</version>
+ <name><![CDATA[dm-hibernate-adapter]]></name>
+ <packaging>java-gem</packaging>
+ <developers>
+ <developer>
+ <id>m_dot_kristian_at_web_dot_de</id>
+ <name>Kristian Meier</name>
+ <email>m.kristian@web.de</email>
+ </developer>
+ <developer>
+ <id>douglasrodrigo_at_gmail_dot_com</id>
+ <name>Douglas Ferreira</name>
+ <email>douglasrodrigo@gmail.com</email>
+ </developer>
+ <developer>
+ <id>piotrgega_at_gmail_dot_com</id>
+ <name>Piotr Gęga</name>
+ <email>piotrgega@gmail.com</email>
+ </developer>
+ </developers>
+ <repositories>
+ <repository>
+ <id>rubygems-releases</id>
+ <url>http://rubygems-proxy.torquebox.org/releases</url>
+ </repository>
+ <repository>
+ <id>jboss</id>
+ <url>https://repository.jboss.org/nexus/content/groups/public-jboss/</url>
+ </repository>
+ </repositories>
+ <pluginRepositories>
+ <pluginRepository>
+ <id>sonatype-snapshots</id>
+ <url>http://oss.sonatype.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+ <dependencies>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>dm-core</artifactId>
+ <version>[1.1.0,1.1.99999]</version>
+ <type>gem</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>dm-transactions</artifactId>
+ <version>[1.1.0,1.1.99999]</version>
+ <type>gem</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>dm-migrations</artifactId>
+ <version>[1.1.0,1.1.99999]</version>
+ <type>gem</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>slf4r</artifactId>
+ <version>0.3.1</version>
+ <type>gem</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>yard</artifactId>
+ <version>0.5.3</version>
+ <type>gem</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>rake</artifactId>
+ <version>0.9.2</version>
+ <type>gem</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>rspec</artifactId>
+ <version>1.3.0</version>
+ <type>gem</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>ruby-maven</artifactId>
+ <version>3.0.3.0.28.5</version>
+ <type>gem</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>rubygems</groupId>
+ <artifactId>jruby-openssl</artifactId>
+ <version>0.7.4</version>
+ <type>gem</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-core</artifactId>
+ <version>3.3.2.GA</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-annotations</artifactId>
+ <version>3.4.0.GA</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-tools</artifactId>
+ <version>3.2.4.GA</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>javax.transaction</groupId>
+ <artifactId>jta</artifactId>
+ <version>1.1</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.8.0.GA</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>mysql</groupId>
+ <artifactId>mysql-connector-java</artifactId>
+ <version>5.1.9</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <version>8.4-701.jdbc4</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <version>1.2.138</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.5.3.0_1</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.hsqldb</groupId>
+ <artifactId>hsqldb</artifactId>
+ <version>2.0.0</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.jruby</groupId>
+ <artifactId>jruby-complete</artifactId>
+ <version>1.6.4</version>
+ <type>jar</type>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.5.2</version>
+ <type>jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <type>jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <properties>
+ <gem.home>${project.build.directory}/rubygems</gem.home>
+ <gem.path>${project.build.directory}/rubygems</gem.path>
+ <jruby.jvmargs>-Xmx1024m</jruby.jvmargs>
+ <jruby.plugins.version>0.28.5-SNAPSHOT</jruby.plugins.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+ <build>
+ <finalName>${project.artifactId}_ext</finalName>
+ <plugins>
+ <plugin>
+ <groupId>de.saumya.mojo</groupId>
+ <artifactId>gem-maven-plugin</artifactId>
+ <version>${jruby.plugins.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <files>lib/dm-hibernate-adapter_ext.jar,lib/dm-hibernate-adapter.rb,lib/dm-hibernate-adapter.rb~,lib/dm-hibernate-adapter,lib/dm-hibernate-adapter/dialects.rb,lib/dm-hibernate-adapter/hibernate.rb~,lib/dm-hibernate-adapter/hibernate.rb,lib/dm-hibernate-adapter/transaction.rb,lib/dm-hibernate-adapter/spec,lib/dm-hibernate-adapter/spec/setup.rb,spec/abstract_adapter,spec/abstract_adapter/spec.opts,spec/abstract_adapter/adapter_shared_spec.rb,spec/abstract_adapter/spec_helper.rb,spec/abstract_adapter/rcov.opts,spec/abstract_adapter/dm-hibernate-adapter_spec.rb,spec/transient,spec/transient/shared,spec/transient/shared/resource_shared_spec.rb,spec/transient/shared/resource_spec.rb,spec/transient/shared/model_spec.rb,spec/transient/shared/adapter_shared_spec.rb,spec/transient/shared/sel_shared_spec.rb,spec/transient/shared/property_spec.rb,spec/transient/shared/finder_shared_spec.rb,spec/transient/lib,spec/transient/lib/collection_helpers.rb,spec/transient/lib/pending_helpers.rb,spec/transient/lib/rspec_immediate_feedback_formatter.rb,spec/transient/lib/counter_adapter.rb,spec/transient/lib/adapter_helpers.rb,spec/transient/spec.opts,spec/transient/spec_helper.rb,spec/transient/rcov.opts,spec/transient/dm-hibernate-adapter_spec.rb,spec/log4j.properties,spec/dm_core,spec/dm_core/adapter_spec.rb,spec/dm_core/spec.opts,spec/dm_core/spec_helper.rb,spec/dm_core/rcov.opts,spec/simple</files>
+ <force>true</force>
+ <gemspec>dm-hibernate-adapter.gemspec</gemspec>
+ <platform>java</platform>
+ <requiredRubygemsVersion><![CDATA[> 1.3.1]]></requiredRubygemsVersion>
+ <testFiles>spec/abstract_adapter/adapter_shared_spec.rb,spec/abstract_adapter/dm-hibernate-adapter_spec.rb,spec/transient/shared/resource_shared_spec.rb,spec/transient/shared/resource_spec.rb,spec/transient/shared/model_spec.rb,spec/transient/shared/adapter_shared_spec.rb,spec/transient/shared/sel_shared_spec.rb,spec/transient/shared/property_spec.rb,spec/transient/shared/finder_shared_spec.rb,spec/transient/dm-hibernate-adapter_spec.rb,spec/dm_core/adapter_spec.rb</testFiles>
+ </configuration>
+ <executions>
+ <execution>
+ <id>in_phase_initialize</id>
+ <phase>initialize</phase>
+ <goals>
+ <goal>execute_in_phase</goal>
+ </goals>
+ <configuration>
+ <file>Mavenfile</file>
+ <phase>initialize</phase>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>de.saumya.mojo</groupId>
+ <artifactId>rspec-maven-plugin</artifactId>
+ <version>${jruby.plugins.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>adapter</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>de.saumya.mojo</groupId>
+ <artifactId>rspec-maven-plugin</artifactId>
+ <configuration>
+ <specSourceDirectory>spec/abstract_adapter</specSourceDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>dm</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>de.saumya.mojo</groupId>
+ <artifactId>rspec-maven-plugin</artifactId>
+ <configuration>
+ <specSourceDirectory>spec/dm_core</specSourceDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>transient</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>de.saumya.mojo</groupId>
+ <artifactId>rspec-maven-plugin</artifactId>
+ <configuration>
+ <specSourceDirectory>spec/transient</specSourceDirectory>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
View
109 src/main/java/dm_hibernate_adapter/JRubyClassLoader.java
@@ -0,0 +1,109 @@
+package dm_hibernate_adapter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.ProtectionDomain;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+public class JRubyClassLoader extends ClassLoader {
+ private org.jruby.util.JRubyClassLoader jrubyClassloader;
+ private Map<String, Class<?>> map = new HashMap<String, Class<?>>();
+
+ public JRubyClassLoader(org.jruby.util.JRubyClassLoader jcl){
+ this.jrubyClassloader = jcl;
+ }
+
+ public void register(Class<?> clazz){
+ map.put(clazz.getName(), clazz);
+ }
+
+ public void clear(){
+ map.clear();
+ }
+
+ @Override
+ public Class<?> loadClass(String name) throws ClassNotFoundException {
+ if(map.containsKey(name)){
+ return map.get(name);
+ }
+ return jrubyClassloader.loadClass(name);
+ }
+
+ public void addURL(URL url) {
+ jrubyClassloader.addURL(url);
+ }
+
+ public void clearAssertionStatus() {
+ jrubyClassloader.clearAssertionStatus();
+ }
+
+ public Class<?> defineClass(String name, byte[] bytes,
+ ProtectionDomain domain) {
+ return jrubyClassloader.defineClass(name, bytes, domain);
+ }
+
+ public Class<?> defineClass(String name, byte[] bytes) {
+ return jrubyClassloader.defineClass(name, bytes);
+ }
+
+ public boolean equals(Object arg0) {
+ return jrubyClassloader.equals(arg0);
+ }
+
+ public URL findResource(String resourceName) {
+ return jrubyClassloader.findResource(resourceName);
+ }
+
+ public Enumeration<URL> findResources(String resourceName)
+ throws IOException {
+ return jrubyClassloader.findResources(resourceName);
+ }
+
+ public Runnable getJDBCDriverUnloader() {
+ return jrubyClassloader.getJDBCDriverUnloader();
+ }
+
+ public URL getResource(String arg0) {
+ return jrubyClassloader.getResource(arg0);
+ }
+
+ public InputStream getResourceAsStream(String arg0) {
+ return jrubyClassloader.getResourceAsStream(arg0);
+ }
+
+ public Enumeration<URL> getResources(String arg0) throws IOException {
+ return jrubyClassloader.getResources(arg0);
+ }
+
+ public URL[] getURLs() {
+ return jrubyClassloader.getURLs();
+ }
+
+ public int hashCode() {
+ return jrubyClassloader.hashCode();
+ }
+
+ public void setClassAssertionStatus(String arg0, boolean arg1) {
+ jrubyClassloader.setClassAssertionStatus(arg0, arg1);
+ }
+
+ public void setDefaultAssertionStatus(boolean arg0) {
+ jrubyClassloader.setDefaultAssertionStatus(arg0);
+ }
+
+ public void setPackageAssertionStatus(String arg0, boolean arg1) {
+ jrubyClassloader.setPackageAssertionStatus(arg0, arg1);
+ }
+
+ public void tearDown(boolean debug) {
+ jrubyClassloader.tearDown(debug);
+ }
+
+ public String toString() {
+ return jrubyClassloader.toString();
+ }
+
+}

0 comments on commit f713bd8

Please sign in to comment.