Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The problem you're having with regards to classloaders is to be expected : if the dependencies of your Eclipse plugins/OSGi bundles are A -> B, with the Clojure jar bootstraped from B, then not being able to see resources of A from B is normal. </p> <p>There can be no cycles among dependencies of Eclipse plugins, so there can be no cycles among classloader hierarchies.</p> <p>This is the same problem that you would face if you were to write extensions to B from A with regular Eclipse machinery : plugin B would declare an interface, and an extension point. Then plugin A could implement the interface, and declare an extension to the extension point. This last part allows the Eclipse framework to do some tricks with the bundles: it sees that A declares an extension to B, thus instanciates a class from A implementing the interface declared in B (this works since A depends on B), and gives B the implementation instance from A which is also OK since it implements the interface in B !</p> <p>(Not sure this is clear).</p> <p><strong>Anyway, back to plugins written in Clojure.</strong><br> With Clojure, you don't have, out of the box, such separate environments provided by classloaders, because everything gets aggregated in one "Clojure environment" living in the classloader realm of the plugin embedding the clojure jar. So one possibility would just be, when plugin A starts, to load the relevant namespaces from A. Then they would be loaded at the right time, and available to any other Clojure code. Another possibility would be to use the Extension Point/Extension machinery. Eclipse provides a way to use "factories" to create instances of extension points. In Counterclockwise, we leverage this feature, and have a generic factory class (written in java, so no AOT) which takes care of loading the right namespace from the right bundle.</p> <p>Here are more detail concerning how to extend extension points.</p> <p><strong>An example from Counterclockwise:</strong><br> There is an existing Extension Point in the Eclipse framework for contributing hyperlink detectors for the Console contents. Counterclockwise extends this extension point to add nrepl hyperlinks.<br> In the java world, you would have to directly declare, in your extension, some class of yours which implements interface IPatternMatchListenerDelegate.<br> But with CCW, for probably the same reasons as you, I try to avoid AOT at all costs, so I can't give a java class name in the extension, or I would have either had to write it in java and compile it, or write a <code>gen-class</code> in Clojure and AOT-compile it.</p> <p>Instead, CCW leverages a hidden gem of plugin.xml's possibilities: in almost every place, when you have to provide a class name, you can instead provide an instance of <a href="http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcore%2Fruntime%2FIExecutableExtensionFactory.html" rel="nofollow">IExecutableExtensionFactory</a> whose <code>create()</code> method will be called by the Eclipse framework to create an instance of the desired class.</p> <p>This allowed me to write a generic class for calling into the Clojure world: I just use, in place of the class name I should have written, the class name <a href="https://github.com/laurentpetit/ccw/blob/master/ccw.util/src/java/ccw/util/GenericExecutableExtension.java" rel="nofollow">ccw.util.GenericExecutableExtension</a></p> <p>Extract from <a href="https://github.com/laurentpetit/ccw/blob/master/ccw.core/plugin.xml#L25" rel="nofollow">plugin.xml</a> :</p> <pre><code>&lt;extension point="org.eclipse.ui.console.consolePatternMatchListeners"&gt; &lt;consolePatternMatchListener id="ccw.editors.clojure.nREPLHyperlink" regex="nrepl://[^':',' ']+:\d+"&gt; &lt;class class="ccw.util.GenericExecutableExtension"&gt; &lt;parameter name="factory" value="ccw.editors.clojure.nrepl-hyperlink/factory"&gt; &lt;/parameter&gt; &lt;/class&gt; &lt;/consolePatternMatchListener&gt; </code></pre> <p>Note the <code>class</code> attribute, and how I can give parameters to the factory via the <code>parameter</code> element (the factory has to implement interface <a href="http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcore%2Fruntime%2FIExecutableExtension.html" rel="nofollow">IExecutableExtension</a> for being able to be initialized with the parameters).</p> <p>Finally, you can see that in namespace <code>ccw.editors.clojure.nrepl-hyperlink</code>, the function <a href="https://github.com/laurentpetit/ccw/blob/master/ccw.core/src/clj/ccw/editors/clojure/nrepl_hyperlink.clj#L27" rel="nofollow">factory</a> is rather simple and just calls the <a href="https://github.com/laurentpetit/ccw/blob/master/ccw.core/src/clj/ccw/editors/clojure/nrepl_hyperlink.clj#L20" rel="nofollow">make</a> function:</p> <pre><code>(defn make [] (let [state (atom nil)] (reify org.eclipse.ui.console.IPatternMatchListenerDelegate (connect [this console] (dosync (reset! state console))) (disconnect [this] (reset! state nil)) (matchFound [this event] (match-found event @state))))) (defn factory "plugin.xml hook" [ _ ] (make)) </code></pre> <p>Please note that I'm showing this as an example, and the relevant code in Counterclockwise is not ready to be released as an independant library "ready for consumption".<br> But you should nonetheless be able to roll your own solution (it's quite easy once you get all the pieces in place in your head).</p> <p>Hope that helps,</p> <p>-- Laurent</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload