Thanks, Guys, for all your help.

Here is an update on where I have got to :

I've given up no trying to aspect the DynamicClassLoader for a while
(maybe forever) as spring/aspecjt/load-time-weaving does not seem to
work at the repl - I've posted another thread regarding this - no
answers as yet.

I've pulled a copy of the latest DynamicClassLoader (DCL) into my own
source tree and hacked it thus :

...
protected static Map<String, byte[]> nameToByteCode = new
HashMap<String, byte[]>();

public static byte[] byteCodeForName(String name) {
        synchronized (nameToByteCode) {
                return nameToByteCode.get(name);
        }
}

public Class defineClass(String name, byte[] bytes, Object srcForm){
        Util.clearCache(rq, classCache);
        Class c = defineClass(name, bytes, 0, bytes.length);
    classCache.put(name, new SoftReference(c,rq));
    synchronized (nameToByteCode) {nameToByteCode.put(name,
bytes);} // this is the point of the hack
    return c;
}

...

I'm not suggesting this as a patch - it doesn't consider GC, lockless
concurrency etc - but simply as a way to test my idea.

I've set up a webserver in my server to serve URLClassLoader requests
for classes created server-side of which instances have been
deserialised client side :

;; only works when URLClassLoader has been given a URL ending in '/'
(defn handle-request [^String target ^Request base-request ^Request
request ^HttpServletResponse response]
  (let [^String path-info (.getPathInfo base-request)
        class-name (.replace (.substring path-info 1 (- (.length path-info)
6)) \/ \.)]
    (if-let [^"[B" bytes (DynamicClassLoader/byteCodeForName class-
name)]
      (let [size (count bytes)]
        (info (str "Serving: " class-name " (" size " bytes)"))
        (doto response
          (.setContentType "application/binary")
          (.setContentLength (count bytes))
          (.setStatus 200))
        (with-open [^OutputStream stream (.getOutputStream response)]
          (doseq [byte bytes] (.write stream (int byte)))))
      (do
        (info (str "Not Serving: " class-name))
        (doto response
          (.setContentLength 0)
          (.setStatus 404)))))
  (.setHandled request true))

(defn ^Server start-jetty [^Integer port]
  (doto (Server. port)
    (.setHandler (proxy [AbstractHandler] [] (handle [& args] (apply
handle-request args))))
    (.start)))

(defn stop-jetty [^Server jetty]
  (.stop jetty))

(start-jetty 8888)

I've installed my own ClassLoader into the hierarchy in the Client
JVM :

  (let [current-thread (Thread/currentThread)]
    (.setContextClassLoader
     current-thread
     (URLClassLoader.
      (into-array [(URL. "http://localhost:8888/";)])
      (.getContextClassLoader current-thread))))

Now for the magic :

server-side:

user=> (defrecord Foo [a b c])
user.Foo
user=> (Foo. 1 2 3)
#:user.Foo{:a 1, :b 2, :c 3}
user=>

and now client-side

user=> (Class/forName "user.Foo")
user.Foo
user=> (Foo. 1 2 3)
CompilerException java.lang.IllegalArgumentException: Unable to
resolve classname: Foo, compiling:(NO_SOURCE_PATH:5)
user=> (user.Foo. 1 2 3)
{:a 1, :b 2, :c 3}
user=>

as you can see - not quite there yet (I seem to have namespace issues)
- but possibilities.

I guess when I called this thread "Serialising functions" I should
have called it "Serialising types" instead, as that is my ultimate
goal.

server-side in response to the requests for unknown classes from the
client I get :

user=> [INFO] web - Serving: user.Foo (9901 bytes)
[INFO] web - Serving: user.Foo$reify__601 (1546 bytes)
[INFO] web - Serving: user.Foo$reify__603 (1546 bytes)
[INFO] web - Not Serving: Foo

looks like trying (Foo. 1 2 3) fell through and looked for user.Foo
again server side...

I then plugged all this in underneath my app to see how it behaved and
I think that I have come up against class name collisions in my client
jvm :

Caused by: java.io.InvalidClassException: org.dada.demo.whales
$fn__330$fn__331; local class incompatible: stream classdesc
serialVersionUID = -2470942646180928550, local class serialVersionUID
= -6698199004290814850
        at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:562)
        at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:
1583)
        at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:
1496)
        at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:
1732)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1667)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1323)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:
1947)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:
1871)
        at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:
1753)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:
1947)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:
1871)
        at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:
1753)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:
1947)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:
1871)
        at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:
1753)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:
1947)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:
1871)
        at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:
1753)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
        at
org.apache.activemq.command.ActiveMQObjectMessage.getObject(ActiveMQObjectMessage.java:
177)
        ... 9 more

This is caused by an object of which the class has already been pulled
by the URLClassLoader, arriving client-side in an ActiveMQMessage but
mistaking a homonymous local class for a remote one of different shape
and trying to use it to deserialise itself - I think.. !

I don't have time to look at this any further today, but I think it is
looking promising if I can find a way to avoid class name collisions -
more hacking of clojure.lang I'm afraid :-(

Apologies for posting all the source code here - but I thought that it
would enable others to follow my track if interested.

That's all for now. I'll post if I get any further.

cheers

Jules

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to