├── nrepl-clojure ├── doc │ └── releases.md ├── project.clj └── src │ └── protege │ ├── model.clj │ ├── nrepl.clj │ └── dialog.clj ├── .gitignore ├── nrepl-plugin ├── plugin.xml ├── src │ └── main │ │ └── java │ │ └── uk │ │ └── org │ │ └── russet │ │ └── protege │ │ └── NreplMenu.java └── pom.xml └── README.md /nrepl-clojure/doc/releases.md: -------------------------------------------------------------------------------- 1 | # Releases 2 | 3 | # 1.0 4 | 5 | First full release. 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /nrepl-clojure/.lein-repl-history 2 | /nrepl-clojure/target 3 | /nrepl-plugin/build 4 | /nrepl-plugin/target 5 | /nrepl-clojure/pom.xml 6 | /nrepl-clojure/src/protege/temp.clj 7 | /nrepl-clojure/test/nrepl_clojure/core_test.clj 8 | /nrepl-plugin/build.properties 9 | /nrepl-plugin/lib/nrepl-clojure.jar 10 | /nrepl-plugin/src/.svn/all-wcprops 11 | /nrepl-plugin/src/.svn/entries 12 | /nrepl-clojure/.lein-failures 13 | /nrepl-clojure/pom.xml.asc 14 | -------------------------------------------------------------------------------- /nrepl-plugin/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /nrepl-clojure/project.clj: -------------------------------------------------------------------------------- 1 | (defproject uk.org.russet/nrepl-clojure "1.1.0-SNAPSHOT" 2 | :description "Launch a nrepl client inside protege" 3 | :license {:name "LGPL" 4 | :url "http://www.gnu.org/licenses/lgpl-3.0.txt" 5 | :distribution :repo} 6 | :scm {:url "https://github.com/phillord/protege-nrepl.git" 7 | :name "git"} 8 | :url "https://github.com/phillord/protege-nrepl" 9 | :dependencies [[org.clojure/clojure "1.6.0"] 10 | [org.clojure/tools.nrepl "0.2.3"] 11 | [edu.stanford.protege/org.protege.editor.core.application 12 | "5.0.0-beta-16-SNAPSHOT"] 13 | [com.cemerick/pomegranate "0.3.0"]] 14 | ;; this is a hack workaround to 15 | ;; https://github.com/technomancy/leiningen/issues/1569 which otherwise adds 16 | ;; nrepl tools as a test dependency in the pom (which means it doesn't get 17 | ;; included in protege-nrepl. 18 | ;; This bug has been fixed in 2.4.3 19 | ;;:profiles {:base {:dependencies ^:replace []}} 20 | ) 21 | -------------------------------------------------------------------------------- /nrepl-clojure/src/protege/model.clj: -------------------------------------------------------------------------------- 1 | ;; The contents of this file are subject to the LGPL License, Version 3.0. 2 | ;; 3 | ;; Copyright (C) 2013, Phillip Lord, Newcastle University 4 | ;; 5 | ;; This program is free software: you can redistribute it and/or modify it 6 | ;; under the terms of the GNU Lesser General Public License as published by 7 | ;; the Free Software Foundation, either version 3 of the License, or (at your 8 | ;; option) any later version. 9 | ;; 10 | ;; This program is distributed in the hope that it will be useful, but WITHOUT 11 | ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | ;; for more details. 14 | ;; 15 | ;; You should have received a copy of the GNU Lesser General Public License 16 | ;; along with this program. If not, see http://www.gnu.org/licenses/. 17 | 18 | (ns protege.model) 19 | 20 | (def ^{:dynamic true 21 | :doc "The OWLModelManager for the Protege Instance from which the REPL 22 | is launched."} 23 | *owl-model-manager* nil) 24 | 25 | (def ^{:dynamic true 26 | :doc "The OWLEditorKit for the Protege Instance from which the REPL is 27 | launched."} 28 | *owl-editor-kit* nil) 29 | 30 | (def ^{:dynamic true 31 | :doc "The OWLWorkspace for the Protege Instance from which the REPL is 32 | launched."} 33 | *owl-work-space* nil) 34 | 35 | (def auto-connect-on-default (ref false)) 36 | 37 | (defn active-ontology 38 | ([] 39 | (.getActiveOntology *owl-model-manager*)) 40 | ([o] 41 | (.setActiveOntology *owl-model-manager* o))) 42 | 43 | 44 | (defn selected-object 45 | ([workspace] 46 | (-> workspace 47 | .getOWLSelectionModel 48 | .getSelectedObject)) 49 | ([workspace entity] 50 | (-> workspace 51 | .getOWLSelectionModel 52 | (.setSelectedObject entity)))) 53 | -------------------------------------------------------------------------------- /nrepl-clojure/src/protege/nrepl.clj: -------------------------------------------------------------------------------- 1 | (ns protege.nrepl 2 | (:require [clojure.tools.nrepl.server] 3 | [clojure.java.io] 4 | [protege.model])) 5 | 6 | 7 | (def nrepl-handler (ref clojure.tools.nrepl.server/default-handler)) 8 | 9 | ;; borrowed from lein 10 | (defn getenv 11 | "Wrap System/getenv for testing purposes." 12 | [name] 13 | (System/getenv name)) 14 | 15 | (defn protege-nrepl-home 16 | "Return full path to the user's protege home directory." 17 | [] 18 | (let [protege-nrepl-home (getenv "PROTEGE_NREPL_HOME") 19 | protege-nrepl-home (or (and protege-nrepl-home (clojure.java.io/file protege-nrepl-home)) 20 | (clojure.java.io/file (System/getProperty "user.home") ".protege-nrepl"))] 21 | (.getAbsolutePath (doto protege-nrepl-home .mkdirs)))) 22 | 23 | (def init 24 | "Load the user's ~/.protege-nrepl/init.clj file, if present." 25 | (memoize (fn [] 26 | (let [init-file (clojure.java.io/file (protege-nrepl-home) "init.clj")] 27 | (when (.exists init-file) 28 | (try (load-file (.getAbsolutePath init-file)) 29 | (catch Exception e 30 | (.printStackTrace e)))))))) 31 | 32 | ;; hook system -- identical to tawny.util -- ah well! 33 | (defn make-hook 34 | "Make a hook." 35 | [] 36 | (atom [])) 37 | 38 | (defn add-hook 39 | "Add func to hook." 40 | [hook func] 41 | (do 42 | (when-not 43 | (some #{func} @hook) 44 | (swap! hook conj func)) 45 | @hook)) 46 | 47 | (defn remove-hook 48 | "Remove func from hook." 49 | [hook func] 50 | (swap! hook 51 | (partial 52 | remove #{func}))) 53 | 54 | (defn clear-hook 55 | "Empty the hook." 56 | [hook] 57 | (reset! hook [])) 58 | 59 | (defn run-hook 60 | "Run the hook with optional arguments. Hook functions are run in the order 61 | that they were added." 62 | ([hook] 63 | (doseq [func @hook] (func))) 64 | ([hook & rest] 65 | (doseq [func @hook] (apply func rest)))) 66 | 67 | 68 | (def start-server-hook (make-hook)) 69 | 70 | (def servers (atom {})) 71 | 72 | 73 | (defn start-server 74 | ([editorkit port] 75 | (binding [protege.model/*owl-editor-kit* editorkit 76 | protege.model/*owl-work-space* 77 | (.getOWLWorkspace editorkit) 78 | protege.model/*owl-model-manager* 79 | (.getOWLModelManager editorkit)] 80 | (run-hook start-server-hook) 81 | (let [server 82 | (clojure.tools.nrepl.server/start-server 83 | :port port 84 | :handler @nrepl-handler)] 85 | (swap! servers assoc editorkit server))))) 86 | 87 | (defn stop-server [editorkit server] 88 | (swap! servers dissoc editorkit) 89 | (clojure.tools.nrepl.server/stop-server server)) 90 | -------------------------------------------------------------------------------- /nrepl-clojure/src/protege/dialog.clj: -------------------------------------------------------------------------------- 1 | (ns protege.dialog 2 | (:require [protege nrepl model]) 3 | (:import [java.awt BorderLayout Color] 4 | [java.awt.event ActionListener] 5 | [javax.swing BoxLayout JButton JLabel JPanel 6 | JTextField])) 7 | 8 | (def last-port (ref 7827)) 9 | ;; map between model manager and port 10 | (def servers (ref {})) 11 | 12 | (defn action-listener [f] 13 | (proxy [ActionListener] [] 14 | (actionPerformed [event] 15 | (f event)))) 16 | 17 | (defn start-server-action [editorkit connect disconnect status event] 18 | (dosync 19 | (let [s (protege.nrepl/start-server 20 | editorkit 21 | @last-port)] 22 | (alter servers merge {editorkit s}) 23 | (.setEnabled disconnect true) 24 | (.setEnabled connect false) 25 | (.setText status 26 | (str "Connected on port: " @last-port) ) 27 | (alter last-port inc)))) 28 | 29 | (defn stop-server-action [editorkit connect disconnect status event] 30 | (dosync 31 | (let [s (get @servers editorkit)] 32 | (alter servers dissoc editorkit) 33 | (.setEnabled connect true) 34 | (.setEnabled disconnect false) 35 | (.setText status "Disconnected") 36 | (protege.nrepl/stop-server editorkit s)))) 37 | 38 | (defn new-dialog-panel [editorkit] 39 | (let [pn (JPanel.) 40 | ;; this one takes so a text box with next available port 41 | ;; and a status bar saying what, er, the status is 42 | middle (JPanel.) 43 | ;; takes a set of buttons, "Connect", "Disconnect", "Close" 44 | ;; greyed as appopriate 45 | south (JPanel.) 46 | button (JPanel.) 47 | port-label (JLabel. "Port") 48 | port (JTextField. (str @last-port) 20) 49 | status (JLabel. "Disconnected") 50 | connect (JButton. "Connect") 51 | disconnect (JButton. "Disconnect") 52 | connect-fn 53 | (partial start-server-action 54 | editorkit 55 | connect disconnect 56 | status)] 57 | (.addActionListener connect 58 | (action-listener connect-fn)) 59 | (doto disconnect 60 | (.setEnabled false) 61 | (.addActionListener 62 | (action-listener 63 | (partial stop-server-action 64 | editorkit connect disconnect 65 | status)))) 66 | 67 | (when @protege.model/auto-connect-on-default 68 | (connect-fn nil)) 69 | 70 | (doto pn 71 | (.setLayout (BorderLayout.)) 72 | (.add middle BorderLayout/CENTER) 73 | (.add south BorderLayout/SOUTH)) 74 | (doto south 75 | (.setLayout (BorderLayout.)) 76 | (.add button BorderLayout/NORTH) 77 | (.add status BorderLayout/SOUTH)) 78 | (doto button 79 | (.setLayout (BoxLayout. button BoxLayout/X_AXIS)) 80 | (.add connect) 81 | (.add disconnect)) 82 | (doto middle 83 | (.setLayout (BorderLayout.)) 84 | (.add port-label BorderLayout/WEST) 85 | (.add port BorderLayout/CENTER)) 86 | pn)) 87 | 88 | 89 | 90 | (defn new-dialog[manager] 91 | (let [fm (javax.swing.JFrame.) 92 | cp (.getContentPane fm)] 93 | (.add cp (new-dialog-panel manager)) 94 | (.pack fm) 95 | (.setVisible fm true) 96 | fm)) 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Protege-Nrepl 2 | ============= 3 | 4 | This is a plugin for the Protege Ontology Editor, which enables 5 | [nrepl](https://github.com/clojure/tools.nrepl) connection to an existing 6 | editor. The [pomegranate](https://github.com/cemerick/pomegranate) library is 7 | included in the bundle, which means that new maven dependencies or classpath 8 | directories can be added dynamically. Access to the Protege internal data 9 | structures is possible, meaning that the Protege instance can be manipulated 10 | remotely. 11 | 12 | Although, it is not tied to it, Protege-Nrepl is being developed for use 13 | with the [Tawny-OWL](https://github.com/phillord/tawny-owl) library; 14 | currently, the release version of Protege and Tawny use different versions of 15 | the OWL API, so a specialized build of Protege is needed. 16 | 17 | ## Build 18 | 19 | Both maven and leiningen are required to build the plugin. To build, 20 | 21 | cd nrepl-plugin 22 | mvn install 23 | 24 | A small `build.sh` script is included which copies the jar file into protege. 25 | 26 | ## Usage 27 | 28 | Install the plugin as a normal Protege plugin. This adds a single menu item 29 | into "Tools", called NREPL, which can be used to launch a REPL for the current 30 | Protege workspace. 31 | 32 | The `protege.model` Clojure namespace provides a number of different vars, 33 | dynamically scoped to the current workspace which you can use to affect the 34 | running Protege instance (if you don't want to do this, there isn't much point 35 | in launching a REPL within Protege!), as well as some utility functions. 36 | 37 | As Clojure itself and the nrepl server, protege-nrepl packages 38 | [pomegranate](https://github.com/cemerick/pomegranate) which enables the 39 | addition of new dependencies or directories to the classpath in the existing 40 | JVM. The easiest way to do this is to use 41 | [lein-sync](https://github.com/phillord/lein-sync) which creates the relevant 42 | function calls from a leiningen project. 43 | 44 | ## Init 45 | 46 | protege-nrepl loads an init file when launching clojure (this happens when the 47 | NREPL menu item is clicked and *not* when Protege is launched. This file is 48 | found at `~/.protege-nrepl/init.clj`, or equivalent on different OSes. 49 | 50 | My `init.clj` is shown in full at 51 | https://github.com/phillord/tawny-protege/README.md, and enables use with 52 | Tawny-OWL. This setting -- which autoconnects a nrepl once the dialog is 53 | started, is generally useful. 54 | 55 | ;; initing the dialog takes ages -- so auto connect 56 | (dosync (ref-set protege.model/auto-connect-on-default true)) 57 | 58 | 59 | ## Mailing List 60 | 61 | There is a [mailing list](mailto:tawny-owl@googlegroups.com) 62 | 63 | ## License 64 | 65 | The contents of this file are subject to the LGPL License, Version 3.0. 66 | 67 | Copyright (C) 2012, 2013, Newcastle University 68 | 69 | This program is free software: you can redistribute it and/or modify it under 70 | the terms of the GNU Lesser General Public License as published by the Free 71 | Software Foundation, either version 3 of the License, or (at your option) any 72 | later version. 73 | 74 | This program is distributed in the hope that it will be useful, but WITHOUT 75 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 76 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 77 | 78 | You should have received a copy of the GNU Lesser General Public License along 79 | with this program. If not, see http://www.gnu.org/licenses/. 80 | -------------------------------------------------------------------------------- /nrepl-plugin/src/main/java/uk/org/russet/protege/NreplMenu.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are subject to the LGPL License, Version 3.0. 3 | * 4 | * Copyright (C) 2013, Phillip Lord, Newcastle University 5 | * 6 | * This program is free software: you can redistribute it and/or modify it 7 | * under the terms of the GNU Lesser General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or (at your 9 | * option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, but WITHOUT 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 14 | * for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with this program. If not, see http://www.gnu.org/licenses/. 18 | */ 19 | package uk.org.russet.protege; 20 | 21 | import clojure.lang.DynamicClassLoader; 22 | import clojure.lang.RT; 23 | import clojure.lang.Var; 24 | 25 | import java.awt.event.ActionEvent; 26 | import java.awt.Container; 27 | import java.awt.BorderLayout; 28 | import javax.swing.JLabel; 29 | import javax.swing.JFrame; 30 | 31 | import javax.swing.JPanel; 32 | import javax.swing.JOptionPane; 33 | import javax.swing.SwingUtilities; 34 | import org.apache.log4j.Logger; 35 | import org.protege.editor.owl.ui.action.ProtegeOWLAction; 36 | 37 | 38 | public class NreplMenu extends ProtegeOWLAction { 39 | private static final long serialVersionUID = -2896209622461162777L; 40 | private static Object lock = new Object(); 41 | private static boolean clojureInit = false; 42 | 43 | private final ClassLoader cl = new DynamicClassLoader(this.getClass().getClassLoader()); 44 | 45 | public void initialise() throws Exception { 46 | } 47 | 48 | 49 | public void dispose() throws Exception { 50 | } 51 | 52 | 53 | 54 | 55 | public void actionPerformed(ActionEvent event) { 56 | Thread.currentThread(). 57 | setContextClassLoader(cl); 58 | 59 | final JFrame frame = new JFrame("REPL connect"); 60 | final Container cp = frame.getContentPane(); 61 | final JLabel initLabel = new JLabel("Initializing Clojure"); 62 | 63 | cp.add(initLabel); 64 | frame.setSize(200,100); 65 | frame.setVisible(true); 66 | frame.validate(); 67 | frame.repaint(); 68 | 69 | final Runnable after = new Runnable(){ 70 | public void run(){ 71 | Thread.currentThread().setContextClassLoader(cl); 72 | Var newDialog = RT.var("protege.dialog", "new-dialog-panel"); 73 | cp.removeAll(); 74 | JPanel dialog = (JPanel)newDialog. 75 | invoke(getOWLEditorKit()); 76 | 77 | cp.add(dialog); 78 | frame.pack(); 79 | frame.setVisible(true); 80 | frame.validate(); 81 | frame.repaint(); 82 | 83 | } 84 | }; 85 | 86 | final Runnable before = new Runnable(){ 87 | public void run(){ 88 | Thread.currentThread().setContextClassLoader(cl); 89 | try{ 90 | if(!clojureInit){ 91 | synchronized(lock){ 92 | RT.loadResourceScript("protege/dialog.clj"); 93 | RT.loadResourceScript("protege/nrepl.clj"); 94 | initLabel.setText("Reading User Init"); 95 | Var init = RT.var("protege.nrepl","init"); 96 | init.invoke(); 97 | clojureInit=true; 98 | } 99 | } 100 | SwingUtilities.invokeAndWait(after); 101 | 102 | } 103 | catch(Exception exp){ 104 | throw new RuntimeException(exp); 105 | } 106 | } 107 | }; 108 | 109 | new Thread(before).start(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /nrepl-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | 6 | org.sonatype.oss 7 | oss-parent 8 | 7 9 | 10 | 11 | 12 | 13 | uk.org.russet 14 | uk.org.russet.protege.nrepl 15 | 0.1.0-SNAPSHOT 16 | protege-nrepl 17 | Provide an NREPL client to use Clojure inside Protege 18 | 19 | bundle 20 | 21 | 22 | 23 | uk.org.russet 24 | nrepl-clojure 25 | 1.1.0-SNAPSHOT 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | edu.stanford.protege 35 | org.protege.editor.core.application 36 | 5.0.0-beta-16-SNAPSHOT 37 | provided 38 | 39 | 40 | edu.stanford.protege 41 | org.protege.editor.owl 42 | 5.0.0-beta-16-SNAPSHOT 43 | provided 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | org.codehaus.mojo 52 | exec-maven-plugin 53 | 1.1 54 | 55 | 56 | compile-with-lein 57 | initialize 58 | 59 | exec 60 | 61 | 62 | 63 | 64 | lein 65 | install 66 | ../nrepl-clojure 67 | 68 | 69 | 70 | org.apache.maven.plugins 71 | maven-compiler-plugin 72 | 3.0 73 | 74 | 1.6 75 | 1.6 76 | 77 | 78 | 79 | org.apache.felix 80 | maven-bundle-plugin 81 | 2.3.7 82 | true 83 | 84 | 85 | . 86 | Protege NREPL 87 | Integrate with Protege through a Clojure Process 88 | ${project.artifactId};singleton:=true 89 | Phil Lord 90 | 97 | 98 | !javax.servlet*,!junit.*,!org.junit*,!org.apache.*, 99 | !org.testng.*,!sun.misc.*, 100 | *, 101 | 102 | 103 | 104 | 105 | 106 | * 107 | plugin.xml,{maven-resources} 108 | true 109 | *;scope=compile|runtime 110 | 115 | 116 | 117 | 118 | bundle-manifest 119 | install 120 | 121 | manifest 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | --------------------------------------------------------------------------------