Skip to content

Commit

Permalink
Remake project structure.
Browse files Browse the repository at this point in the history
Structure:

- `liverepl-agent` becomes `client` and `agent` (duplicates LOCALHOST
  definition)
- `liverepl-server` becomes `server`
- project.clj munging, including use of lein-jdk-tools

Code changes:

- Server incorporates Clojure as uberjar
- Agent checks whether server is loaded, not whether clojure is
- Main and shell script no longer pass location of clojure jar
- Fix generics in Discovery (gets rid of warning)
- shell script uses new build locations
- shell script specifies bash in shebang

Documentation:

- Change README to Markdown, include contributors
- Fix licensing in project.clj to mention MIT License and refer
  to README for contributors
  • Loading branch information
timmc-bcov committed Oct 24, 2014
1 parent 417fb2d commit c32d56e
Show file tree
Hide file tree
Showing 23 changed files with 163 additions and 127 deletions.
11 changes: 5 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
# IDE settings
**/.classpath
**/.project
**/.settings
**/*.jardesc
**/.settings/**
/*/.classpath
/*/.project
/*/.settings
/*/*.jardesc
/*/.settings/

# Manually added artifacts
/liverepl-server/lib/clojure.jar
/jars/

# Build artifacts
Expand Down
68 changes: 0 additions & 68 deletions README.TXT

This file was deleted.

79 changes: 79 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
LiveRepl
========

Start a Clojure REPL connected to any running Java or Clojure process
without needing the process to be setup in any special way beforehand.

Now supports connecting to Tomcat web applications.

You can use the repl to run code, inspect variables, and
redefine Clojure functions.

Build
-----

To build:

```
(cd client; lein uberjar) && (cd agent; lein jar) && (cd server; lein uberjar)
```

This produces jar files in the following locations:

```
client/target/liverepl-client-standalone.jar
agent/target/liverepl-agent.jar
server/target/liverepl-server-standalone.jar
```

Operation
---------

Call liverepl.sh as follows:

```
export JDK_HOME=/usr/lib/jvm/java-7-oracle
./liverepl.sh
```

To see a list of running Java processes on the system, and their
process ids, enter:

liverepl.sh

To see the available ClassLoaders for a specific process, enter:

liverepl.sh <pid>

-- where the pid is the process id for the process, obtained in
the step above.

To connect a repl to the process, enter:

liverepl.sh <pid> <classloader-id>

-- where the pid is the process id for the process.
-- and the classloader-id was obtained in the step above.

If you aren't sure which ClassLoader to use, try '0', which will
always be the System ClassLoader.

If the directory `./jars/` is present in the same location as
liverepl.sh, any jars inside will be loaded and made available inside
the target JVM. They must be at the top level inside the directory and
have a name ending in `.jar`.

License and credits
-------------------

This software is distributed under the MIT licence.

http://github.com/djpowell/liverepl

Original author: David Powell <djpowell@djpowell.net> 2009-10-18

Other contributions by:

- Kurt Harriger
- Kevin A. Archie
- Brightcove, Inc. (authors Chris Jeris, Tim McCormack)
13 changes: 13 additions & 0 deletions agent/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(defproject com.brightcove.liverepl/agent "0.1.1-SNAPSHOT"
:description "LiveREPL agent"
:license {:name "MIT License"
:distribution :repo
:comments "Copyright (C) 2009 David J. Powell and others. See README for contributors."}
:url "https://github.com/djpowell/liverepl"
:min-lein-version "2.0.0"
:dependencies []
:source-paths []
:java-source-paths ["src"]
:manifest {"Agent-Class" "net.djpowell.liverepl.agent.Agent"}
:lein-release {:scm :git, :deploy-via :lein-install}
:jar-name "liverepl-agent.jar")
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Logger;

import net.djpowell.liverepl.client.Main;
import net.djpowell.liverepl.discovery.ClassLoaderInfo;
import net.djpowell.liverepl.discovery.Discovery;

public class Agent {

// bind to localhost to keep things more secure
public static final InetAddress LOCALHOST;
static {
try {
LOCALHOST = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}

private static final Discovery discovery = new Discovery();

public static interface ConnectNotifyingTask {
Expand Down Expand Up @@ -46,7 +55,7 @@ public void run() {
}

public static void runAfterConnect(int port, int connectTimeout, String threadName, final ConnectNotifyingTask task) throws Exception {
final ServerSocket serverSocket = new ServerSocket(port, 0, Main.LOCALHOST);
final ServerSocket serverSocket = new ServerSocket(port, 0, LOCALHOST);
final AtomicBoolean connected = new AtomicBoolean(false);
Thread taskThread = new Thread(new Runnable() {
public void run() {
Expand Down Expand Up @@ -107,10 +116,10 @@ private static void popClassLoader(ClassLoader old) {
Thread.currentThread().setContextClassLoader(old);
}

private static boolean isClojureLoaded() {
private static boolean isServerLoaded() {
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
cl.loadClass("clojure.lang.RT");
cl.loadClass("net.djpowell.liverepl.server.Repl");
return true;
} catch (ClassNotFoundException e) {
return false;
Expand All @@ -121,13 +130,12 @@ public static void agentmain(String agentArgs, Instrumentation inst) {
TRC.fine("Started Attach agent");

StringTokenizer stok = new StringTokenizer(agentArgs, "\n");
if (stok.countTokens() != 5) {
if (stok.countTokens() != 4) {
throw new RuntimeException("Invalid parameters: " + agentArgs);
}

int port = Integer.parseInt(stok.nextToken());
TRC.fine("Port: " + port);
String clojurePath = stok.nextToken();
String serverPath = stok.nextToken();
String jarsPath = stok.nextToken();
String classLoaderId = stok.nextToken();
Expand All @@ -137,14 +145,14 @@ public static void agentmain(String agentArgs, Instrumentation inst) {
return;
}

boolean clojureLoaded = isClojureLoaded();
TRC.fine("Clojure is " + (clojureLoaded ? "" : "not ") + "loaded");
boolean serverLoaded = isServerLoaded();
TRC.fine("Server is " + (serverLoaded ? "" : "not ") + "loaded");

List<URL> urls;
if (clojureLoaded) {
urls = getJarUrls(serverPath);
if (serverLoaded) {
urls = new ArrayList<URL>();
} else {
urls = getJarUrls(clojurePath, serverPath);
urls = getJarUrls(serverPath);
}
File jarsDir = new File(jarsPath);
if (jarsDir.exists()) {
Expand All @@ -162,8 +170,8 @@ public boolean accept(File dir, String path) {

ClassLoader old = pushClassLoader(urls, classLoaderId);
try {
if (!clojureLoaded) { // if clojure wasn't loaded before, print current status
TRC.fine("Clojure is " + (isClojureLoaded() ? "" : "not ") + "loaded");
if (!serverLoaded) { // if server wasn't loaded before, print current status
TRC.fine("Server is " + (isServerLoaded() ? "" : "not ") + "loaded");
}
startRepl(port, inst);
} finally {
Expand Down Expand Up @@ -195,7 +203,7 @@ private static void startRepl(int port, Instrumentation inst) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class<?> repl = Class.forName("net.djpowell.liverepl.server.Repl", true, cl);
Method method = repl.getMethod("main", InetAddress.class, Integer.TYPE, Instrumentation.class);
method.invoke(null, Main.LOCALHOST, port, inst);
method.invoke(null, LOCALHOST, port, inst);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public Discovery() {
}

public Collection<ClassLoaderInfo> listClassLoaders() {
List<ClassLoaderInfo> ret = new ArrayList();
List<ClassLoaderInfo> ret = new ArrayList<ClassLoaderInfo>();
for (ClassLoaderDiscovery discovery : impls) {
ret.addAll(discovery.listClassLoaders());
}
Expand Down
16 changes: 16 additions & 0 deletions client/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(defproject com.brightcove.liverepl/client "0.1.1-SNAPSHOT"
:description "LiveREPL client"
:license {:name "MIT License"
:distribution :repo
:comments "Copyright (C) 2009 David J. Powell and others. See README for contributors."}
:url "https://github.com/djpowell/liverepl"
:min-lein-version "2.0.0"
:dependencies []
:source-paths []
:java-source-paths ["src"]
:plugins [[lein-jdk-tools "0.1.1"]]
;; Mention :skip-aot to suppress warning
:main ^:skip-aot net.djpowell.liverepl.client.Main
:lein-release {:scm :git, :deploy-via :lein-install}
:uberjar-exclusions [#"^.*\.jar$"]
:uberjar-name "liverepl-client-standalone.jar")
Original file line number Diff line number Diff line change
Expand Up @@ -48,31 +48,30 @@ private static void listPids() {
}

public static void main(String[] args) throws Exception {
// Usage: <clojurepath> <agentjarpath> <serverjarpath> <jarsdir> <jvmpid> <classloaderid>
if (args.length < 5) {
// Usage: <agentjarpath> <serverjarpath> <jarsdir> <jvmpid> <classloaderid>
if (args.length < 4) {
listPids();
System.exit(0);
}
String clojurepath = args[0];
String agentpath = args[1];
String serverpath = args[2];
String jarsdir = args[3];
String pid = args[4];
String agentpath = args[0];
String serverpath = args[1];
String jarsdir = args[2];
String pid = args[3];
String classLoaderId;
if (args.length < 6) {
if (args.length < 5) {
classLoaderId = "L";
System.out.println();
System.out.println("List of ClassLoaders for process #" + pid);
} else {
classLoaderId = args[5];
classLoaderId = args[4];
}

TRC.fine("Attaching to pid: " + pid);
final VirtualMachine vm = VirtualMachine.attach(pid);

int port = getFreePort(LOCALHOST);
// start the agent, which will create the server socket, then return
String agentArgs = String.valueOf(port) + "\n" + clojurepath + "\n" + serverpath + "\n" + jarsdir + "\n" + classLoaderId;
String agentArgs = String.valueOf(port) + "\n" + serverpath + "\n" + jarsdir + "\n" + classLoaderId;
vm.loadAgent(agentpath, agentArgs);

boolean listClassLoaders = "L".equals(classLoaderId);
Expand Down
11 changes: 0 additions & 11 deletions liverepl-agent/project.clj

This file was deleted.

10 changes: 0 additions & 10 deletions liverepl-server/project.clj

This file was deleted.

Loading

0 comments on commit c32d56e

Please sign in to comment.