Class: Jenkins::Plugin::Proxies
- Inherits:
-
Object
- Object
- Jenkins::Plugin::Proxies
- Defined in:
- lib/jenkins/plugin/proxies.rb
Overview
Maps JRuby objects part of the idomatic Ruby API to a plain Java object representation and vice-versa.
One of the pillars of Jenkins Ruby plugins is that writing plugins must “feel” like native Ruby, and not merely like scripting Java with Ruby. To this end, jenkins-plugins provides a idiomatic Ruby API that sits on top of the native Jenkins Java API with which plugin developers can interact.
This has two consequences. Native Ruby objects authored as part of the plugin must have a foreign (Java) representation with which they can wander about the Jenkins universe and possibly interact with other foreign objects and APIs. Also, Foreign objects coming in from Jenkins at large should be wrapped, where possible to present an idomatic interface..
Finally, Native plugin that had been wrapped and are comping home must be unwrapped from their external form.
For all cases, we want to maintain referential integrety so that the same object always uses the same external form, etc… so there is one instance of the ‘Proxies` class per plugin which will reuse mappings where possible.
Class Method Summary collapse
-
.clear ⇒ Object
Remove all class linkages.
-
.register(internal_class, external_class) ⇒ Object
Associated the the Ruby class ‘internal_class` with the Java class `external_class`.
Instance Method Summary collapse
- #deref(reflist, object) ⇒ Object
-
#export(object) ⇒ java.lang.Object
Reflect a native Ruby object into its External Java form.
-
#import(object) ⇒ Object
Reflect a foreign Java object into the context of this plugin.
-
#initialize(plugin) ⇒ Proxies
constructor
A new instance of Proxies.
-
#linkin(internal, external) ⇒ Object
Forms an incoming reference to an internal Ruby object from an external Java object.
-
#linkout(internal, external) ⇒ Object
Forms an outgoing reference from an internal Ruby object to an external Java object.
Constructor Details
#initialize(plugin) ⇒ Proxies
Returns a new instance of Proxies.
35 36 37 38 39 |
# File 'lib/jenkins/plugin/proxies.rb', line 35 def initialize(plugin) @plugin = plugin @int2ext = java.util.Collections.synchronizedMap(java.util.WeakHashMap.new) @ext2int = java.util.Collections.synchronizedMap(java.util.WeakHashMap.new) end |
Class Method Details
.clear ⇒ Object
Remove all class linkages. This is mainly for testing purposes.
165 166 167 168 |
# File 'lib/jenkins/plugin/proxies.rb', line 165 def self.clear @@intcls2extcls = {} @@extcls2intcls = {} end |
.register(internal_class, external_class) ⇒ Object
Associated the the Ruby class ‘internal_class` with the Java class `external_class`.
Whenever a plugin is importing or exporting an object to the other side, it will first see if there is an instance already linked. If not, it will try to create the other side of the link by constructing it via reflection. ‘register` links two classes together so that links can be built automatically.
158 159 160 161 |
# File 'lib/jenkins/plugin/proxies.rb', line 158 def self.register(internal_class, external_class) @@intcls2extcls[internal_class] = external_class @@extcls2intcls[external_class] = internal_class end |
Instance Method Details
#deref(reflist, object) ⇒ Object
142 143 144 145 146 |
# File 'lib/jenkins/plugin/proxies.rb', line 142 def deref(reflist, object) if ref = reflist[object] ref.is_a?(java.lang.ref.Reference) ? ref.get() : ref end end |
#export(object) ⇒ java.lang.Object
Reflect a native Ruby object into its External Java form.
Try to find a suitable form for this object and if one is found then decorate it. If the object already is a java.lang.Object, then just let it pass through.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/jenkins/plugin/proxies.rb', line 77 def export(object) if proxy = deref(@int2ext, object) return proxy end cls = object.class if cls.respond_to? :java_class return object end while cls do if external_class = @@intcls2extcls[cls] external = external_class.new(@plugin, object) linkout(object, external) return external end cls = cls.superclass end raise ExportError, "unable to find suitable Java Proxy for #{object.inspect}" end |
#import(object) ⇒ Object
Reflect a foreign Java object into the context of this plugin.
If the object is a native plugin object that had been previously exported, then it will unwrapped.
Otherwise, we try to choose the best idiomatic API object for this foreign object
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/jenkins/plugin/proxies.rb', line 51 def import(object) if proxy = deref(@ext2int, object) return proxy end cls = object.class while cls do if internal_class = @@extcls2intcls[cls] internal = internal_class.new(object) linkin(internal, object) return internal end cls = cls.superclass end internal = OpaqueJavaObject.new(object) linkin(internal, object) return internal end |
#linkin(internal, external) ⇒ Object
Forms an incoming reference to an internal Ruby object from an external Java object. These two objects will be referentially equivalent whenever they are passed back and forth between the Ruby plugin and the Jenkins runtime.
The fact that this reference is “in” means that GC-wise, the internal Ruby object depends on the external Java object. In other words, it will not be garbage collected until the Java object is.
This behavior is important for things like AbstractBuild objects. We don’t want our Ruby ‘Build` object that corresponds to it to be GC’d until the ‘hudson.model.AbstractBuild` it represents is itself collected. That allows us to maintain state on the Ruby object, and know that the same state will be accessible wherever.
Only weak refereces are maintained to the external Java object.
118 119 120 121 |
# File 'lib/jenkins/plugin/proxies.rb', line 118 def linkin(internal, external) @int2ext.put(internal, java.lang.ref.WeakReference.new(external)) @ext2int.put(external, internal) end |
#linkout(internal, external) ⇒ Object
Forms an outgoing reference from an internal Ruby object to an external Java object. These two objects will be referentially equivalent whenever they are passed back and forth between the Ruby plugin and the Jenkins runtime.
The fact that this reference goes “out” means that GC-wise, the external Java object depends on the internal Ruby object. In other words, The Java object will not be garbage collected until the local Ruby object is.
Only weak refereces are maintained to the internal Ruby object.
137 138 139 140 |
# File 'lib/jenkins/plugin/proxies.rb', line 137 def linkout(internal, external) @int2ext.put(internal, external) @ext2int.put(external, java.lang.ref.WeakReference.new(internal)) end |